From 37e595f0ce073a9f6cc19b03f77564b7e67819da Mon Sep 17 00:00:00 2001 From: wanttobeno Date: Wed, 10 Jun 2020 18:11:21 +0800 Subject: [PATCH] init --- ChartDemo.exe | Bin 0 -> 114688 bytes ChartDemo/ChartCtrl/ChartAxis.cpp | 850 ++++++++++++ ChartDemo/ChartCtrl/ChartAxis.h | 526 +++++++ ChartDemo/ChartCtrl/ChartAxisLabel.cpp | 157 +++ ChartDemo/ChartCtrl/ChartAxisLabel.h | 112 ++ ChartDemo/ChartCtrl/ChartBalloonLabel.h | 101 ++ ChartDemo/ChartCtrl/ChartBalloonLabel.inl | 138 ++ ChartDemo/ChartCtrl/ChartBarSerie.cpp | 392 ++++++ ChartDemo/ChartCtrl/ChartBarSerie.h | 203 +++ ChartDemo/ChartCtrl/ChartCandlestickSerie.cpp | 243 ++++ ChartDemo/ChartCtrl/ChartCandlestickSerie.h | 142 ++ ChartDemo/ChartCtrl/ChartCrossHairCursor.cpp | 62 + ChartDemo/ChartCtrl/ChartCrossHairCursor.h | 72 + ChartDemo/ChartCtrl/ChartCtrl.cpp | 1143 ++++++++++++++++ ChartDemo/ChartCtrl/ChartCtrl.h | 586 ++++++++ ChartDemo/ChartCtrl/ChartCtrl_source.zip | Bin 0 -> 108508 bytes ChartDemo/ChartCtrl/ChartCursor.cpp | 56 + ChartDemo/ChartCtrl/ChartCursor.h | 125 ++ ChartDemo/ChartCtrl/ChartDateTimeAxis.cpp | 411 ++++++ ChartDemo/ChartCtrl/ChartDateTimeAxis.h | 150 ++ ChartDemo/ChartCtrl/ChartDragLineCursor.cpp | 103 ++ ChartDemo/ChartCtrl/ChartDragLineCursor.h | 72 + ChartDemo/ChartCtrl/ChartFont.cpp | 145 ++ ChartDemo/ChartCtrl/ChartFont.h | 111 ++ ChartDemo/ChartCtrl/ChartGanttSerie.cpp | 228 ++++ ChartDemo/ChartCtrl/ChartGanttSerie.h | 162 +++ ChartDemo/ChartCtrl/ChartGradient.cpp | 127 ++ ChartDemo/ChartCtrl/ChartGradient.h | 65 + ChartDemo/ChartCtrl/ChartGrid.cpp | 123 ++ ChartDemo/ChartCtrl/ChartGrid.h | 83 ++ ChartDemo/ChartCtrl/ChartLabel.h | 122 ++ ChartDemo/ChartCtrl/ChartLabel.inl | 59 + ChartDemo/ChartCtrl/ChartLegend.cpp | 357 +++++ ChartDemo/ChartCtrl/ChartLegend.h | 155 +++ ChartDemo/ChartCtrl/ChartLineSerie.cpp | 360 +++++ ChartDemo/ChartCtrl/ChartLineSerie.h | 114 ++ ChartDemo/ChartCtrl/ChartLogarithmicAxis.cpp | 190 +++ ChartDemo/ChartCtrl/ChartLogarithmicAxis.h | 62 + ChartDemo/ChartCtrl/ChartMouseListener.h | 90 ++ ChartDemo/ChartCtrl/ChartPointsArray.h | 170 +++ ChartDemo/ChartCtrl/ChartPointsArray.inl | 351 +++++ ChartDemo/ChartCtrl/ChartPointsSerie.cpp | 335 +++++ ChartDemo/ChartCtrl/ChartPointsSerie.h | 117 ++ ChartDemo/ChartCtrl/ChartScrollBar.cpp | 222 +++ ChartDemo/ChartCtrl/ChartScrollBar.h | 75 + ChartDemo/ChartCtrl/ChartSerie.cpp | 150 ++ ChartDemo/ChartCtrl/ChartSerie.h | 283 ++++ ChartDemo/ChartCtrl/ChartSerieBase.h | 231 ++++ ChartDemo/ChartCtrl/ChartSerieBase.inl | 340 +++++ .../ChartCtrl/ChartSeriesMouseListener.h | 65 + ChartDemo/ChartCtrl/ChartStandardAxis.cpp | 197 +++ ChartDemo/ChartCtrl/ChartStandardAxis.h | 76 ++ ChartDemo/ChartCtrl/ChartString.h | 33 + ChartDemo/ChartCtrl/ChartSurfaceSerie.cpp | 289 ++++ ChartDemo/ChartCtrl/ChartSurfaceSerie.h | 128 ++ ChartDemo/ChartCtrl/ChartTitle.cpp | 201 +++ ChartDemo/ChartCtrl/ChartTitle.h | 136 ++ ChartDemo/ChartCtrl/ChartXYSerie.cpp | 186 +++ ChartDemo/ChartCtrl/ChartXYSerie.h | 157 +++ ChartDemo/ChartCtrl/PointsOrdering.h | 33 + ChartDemo/ChartDemo.cpp | 76 ++ ChartDemo/ChartDemo.dsp | 440 ++++++ ChartDemo/ChartDemo.dsw | 29 + ChartDemo/ChartDemo.h | 49 + ChartDemo/ChartDemo.rc | 454 +++++++ ChartDemo/ChartDemo.sln | 20 + ChartDemo/ChartDemo.vcproj | 656 +++++++++ ChartDemo/ChartDemoDlg.cpp | 751 ++++++++++ ChartDemo/ChartDemoDlg.h | 82 ++ ChartDemo/ColourPicker/ColourPicker.cpp | 309 +++++ ChartDemo/ColourPicker/ColourPicker.h | 113 ++ ChartDemo/ColourPicker/ColourPopup.cpp | 917 +++++++++++++ ChartDemo/ColourPicker/ColourPopup.h | 132 ++ ChartDemo/Doc/html/_chart_axis_8h-source.html | 265 ++++ .../Doc/html/_chart_axis_label_8h-source.html | 104 ++ .../Doc/html/_chart_axis_old_8h-source.html | 239 ++++ .../html/_chart_balloon_label_8h-source.html | 95 ++ .../Doc/html/_chart_bar_serie_8h-source.html | 148 ++ .../_chart_candlestick_serie_8h-source.html | 110 ++ .../_chart_cross_hair_cursor_8h-source.html | 77 ++ ChartDemo/Doc/html/_chart_ctrl_8h-source.html | 305 +++++ .../Doc/html/_chart_cursor_8h-source.html | 105 ++ .../html/_chart_date_time_axis_8h-source.html | 109 ++ ChartDemo/Doc/html/_chart_demo_8h-source.html | 72 + .../Doc/html/_chart_demo_dlg_8h-source.html | 108 ++ .../_chart_drag_line_cursor_8h-source.html | 81 ++ ChartDemo/Doc/html/_chart_font_8h-source.html | 94 ++ .../html/_chart_gantt_serie_8h-source.html | 116 ++ .../Doc/html/_chart_gradient_8h-source.html | 69 + ChartDemo/Doc/html/_chart_grid_8h-source.html | 93 ++ .../Doc/html/_chart_label_8h-source.html | 104 ++ .../Doc/html/_chart_legend_8h-source.html | 130 ++ .../Doc/html/_chart_line_serie_8h-source.html | 95 ++ .../_chart_logarithmic_axis_8h-source.html | 82 ++ .../html/_chart_mouse_listener_8h-source.html | 83 ++ .../Doc/html/_chart_object_8h-source.html | 126 ++ .../html/_chart_point_label_8h-source.html | 107 ++ .../html/_chart_points_array_8h-source.html | 112 ++ .../html/_chart_points_serie_8h-source.html | 102 ++ .../Doc/html/_chart_scroll_bar_8h-source.html | 84 ++ .../Doc/html/_chart_serie_8h-source.html | 164 +++ .../Doc/html/_chart_serie_base_8h-source.html | 139 ++ ...chart_series_mouse_listener_8h-source.html | 72 + .../html/_chart_standard_axis_8h-source.html | 84 ++ .../Doc/html/_chart_string_8h-source.html | 60 + .../html/_chart_surface_serie_8h-source.html | 102 ++ .../Doc/html/_chart_title_8h-source.html | 109 ++ .../Doc/html/_chart_x_y_serie_8h-source.html | 115 ++ .../Doc/html/_colour_picker_8h-source.html | 136 ++ .../Doc/html/_colour_popup_8h-source.html | 156 +++ .../Doc/html/_line_prop_dialog_8h-source.html | 72 + .../Doc/html/_points_ordering_8h-source.html | 56 + .../html/_points_prop_dialog_8h-source.html | 74 + .../Doc/html/_series_prop_dlg_8h-source.html | 109 ++ ChartDemo/Doc/html/_std_afx_8h-source.html | 53 + .../html/_surface_prop_dialog_8h-source.html | 72 + ChartDemo/Doc/html/annotated.html | 67 + .../Doc/html/class_c_chart_axis-members.html | 98 ++ ChartDemo/Doc/html/class_c_chart_axis.html | 964 +++++++++++++ ChartDemo/Doc/html/class_c_chart_axis.png | Bin 0 -> 913 bytes .../class_c_chart_axis_label-members.html | 40 + .../Doc/html/class_c_chart_axis_label.html | 142 ++ .../class_c_chart_balloon_label-members.html | 57 + .../Doc/html/class_c_chart_balloon_label.html | 181 +++ .../Doc/html/class_c_chart_balloon_label.png | Bin 0 -> 613 bytes .../html/class_c_chart_bar_serie-members.html | 119 ++ .../Doc/html/class_c_chart_bar_serie.html | 293 ++++ .../Doc/html/class_c_chart_bar_serie.png | Bin 0 -> 831 bytes ...ass_c_chart_candlestick_serie-members.html | 96 ++ .../html/class_c_chart_candlestick_serie.html | 285 ++++ .../html/class_c_chart_candlestick_serie.png | Bin 0 -> 875 bytes ...ass_c_chart_cross_hair_cursor-members.html | 48 + .../html/class_c_chart_cross_hair_cursor.html | 65 + .../html/class_c_chart_cross_hair_cursor.png | Bin 0 -> 468 bytes .../Doc/html/class_c_chart_ctrl-members.html | 109 ++ ChartDemo/Doc/html/class_c_chart_ctrl.html | 1206 +++++++++++++++++ .../html/class_c_chart_cursor-members.html | 48 + ChartDemo/Doc/html/class_c_chart_cursor.html | 225 +++ ChartDemo/Doc/html/class_c_chart_cursor.png | Bin 0 -> 750 bytes ...class_c_chart_cursor_listener-members.html | 35 + .../html/class_c_chart_cursor_listener.html | 103 ++ .../class_c_chart_date_time_axis-members.html | 101 ++ .../html/class_c_chart_date_time_axis.html | 181 +++ .../Doc/html/class_c_chart_date_time_axis.png | Bin 0 -> 447 bytes ...lass_c_chart_drag_line_cursor-members.html | 49 + .../html/class_c_chart_drag_line_cursor.html | 78 ++ .../html/class_c_chart_drag_line_cursor.png | Bin 0 -> 480 bytes .../Doc/html/class_c_chart_font-members.html | 41 + ChartDemo/Doc/html/class_c_chart_font.html | 238 ++++ .../class_c_chart_gantt_serie-members.html | 102 ++ .../Doc/html/class_c_chart_gantt_serie.html | 331 +++++ .../Doc/html/class_c_chart_gantt_serie.png | Bin 0 -> 721 bytes .../html/class_c_chart_gradient-members.html | 35 + .../Doc/html/class_c_chart_gradient.html | 118 ++ .../Doc/html/class_c_chart_grid-members.html | 36 + ChartDemo/Doc/html/class_c_chart_grid.html | 63 + .../Doc/html/class_c_chart_label-members.html | 46 + ChartDemo/Doc/html/class_c_chart_label.html | 183 +++ ChartDemo/Doc/html/class_c_chart_label.png | Bin 0 -> 414 bytes .../class_c_chart_label_provider-members.html | 35 + .../html/class_c_chart_label_provider.html | 103 ++ .../html/class_c_chart_legend-members.html | 51 + ChartDemo/Doc/html/class_c_chart_legend.html | 169 +++ .../class_c_chart_line_serie-members.html | 107 ++ .../Doc/html/class_c_chart_line_serie.html | 171 +++ .../Doc/html/class_c_chart_line_serie.png | Bin 0 -> 824 bytes ...lass_c_chart_logarithmic_axis-members.html | 86 ++ .../html/class_c_chart_logarithmic_axis.html | 55 + .../html/class_c_chart_logarithmic_axis.png | Bin 0 -> 468 bytes .../class_c_chart_mouse_listener-members.html | 46 + .../html/class_c_chart_mouse_listener.html | 237 ++++ .../class_c_chart_points_array-members.html | 51 + .../Doc/html/class_c_chart_points_array.html | 351 +++++ .../class_c_chart_points_serie-members.html | 112 ++ .../Doc/html/class_c_chart_points_serie.html | 141 ++ .../Doc/html/class_c_chart_points_serie.png | Bin 0 -> 844 bytes .../class_c_chart_scroll_bar-members.html | 42 + .../Doc/html/class_c_chart_scroll_bar.html | 109 ++ .../Doc/html/class_c_chart_serie-members.html | 75 + ChartDemo/Doc/html/class_c_chart_serie.html | 737 ++++++++++ ChartDemo/Doc/html/class_c_chart_serie.png | Bin 0 -> 3251 bytes .../class_c_chart_serie_base-members.html | 91 ++ .../Doc/html/class_c_chart_serie_base.html | 672 +++++++++ .../Doc/html/class_c_chart_serie_base.png | Bin 0 -> 460 bytes ...c_chart_series_mouse_listener-members.html | 35 + .../class_c_chart_series_mouse_listener.html | 115 ++ .../class_c_chart_standard_axis-members.html | 93 ++ .../Doc/html/class_c_chart_standard_axis.html | 119 ++ .../Doc/html/class_c_chart_standard_axis.png | Bin 0 -> 457 bytes .../class_c_chart_surface_serie-members.html | 114 ++ .../Doc/html/class_c_chart_surface_serie.html | 188 +++ .../Doc/html/class_c_chart_surface_serie.png | Bin 0 -> 860 bytes .../Doc/html/class_c_chart_title-members.html | 45 + ChartDemo/Doc/html/class_c_chart_title.html | 241 ++++ .../html/class_c_chart_x_y_serie-members.html | 103 ++ .../Doc/html/class_c_chart_x_y_serie.html | 377 ++++++ .../Doc/html/class_c_chart_x_y_serie.png | Bin 0 -> 1944 bytes ChartDemo/Doc/html/classes.html | 36 + ChartDemo/Doc/html/deprecated.html | 33 + ChartDemo/Doc/html/doxygen.css | 441 ++++++ ChartDemo/Doc/html/doxygen.png | Bin 0 -> 1281 bytes ChartDemo/Doc/html/files.html | 62 + ChartDemo/Doc/html/functions.html | 89 ++ ChartDemo/Doc/html/functions_0x63.html | 147 ++ ChartDemo/Doc/html/functions_0x64.html | 96 ++ ChartDemo/Doc/html/functions_0x65.html | 84 ++ ChartDemo/Doc/html/functions_0x66.html | 73 + ChartDemo/Doc/html/functions_0x67.html | 248 ++++ ChartDemo/Doc/html/functions_0x68.html | 71 + ChartDemo/Doc/html/functions_0x69.html | 96 ++ ChartDemo/Doc/html/functions_0x6c.html | 71 + ChartDemo/Doc/html/functions_0x6d.html | 144 ++ ChartDemo/Doc/html/functions_0x6e.html | 75 + ChartDemo/Doc/html/functions_0x6f.html | 108 ++ ChartDemo/Doc/html/functions_0x70.html | 77 ++ ChartDemo/Doc/html/functions_0x72.html | 102 ++ ChartDemo/Doc/html/functions_0x73.html | 245 ++++ ChartDemo/Doc/html/functions_0x74.html | 71 + ChartDemo/Doc/html/functions_0x75.html | 79 ++ ChartDemo/Doc/html/functions_0x76.html | 78 ++ ChartDemo/Doc/html/functions_0x78.html | 75 + ChartDemo/Doc/html/functions_0x79.html | 75 + ChartDemo/Doc/html/functions_0x7e.html | 111 ++ ChartDemo/Doc/html/functions_enum.html | 58 + ChartDemo/Doc/html/functions_eval.html | 50 + ChartDemo/Doc/html/functions_func.html | 84 ++ ChartDemo/Doc/html/functions_func_0x63.html | 140 ++ ChartDemo/Doc/html/functions_func_0x64.html | 89 ++ ChartDemo/Doc/html/functions_func_0x65.html | 73 + ChartDemo/Doc/html/functions_func_0x67.html | 243 ++++ ChartDemo/Doc/html/functions_func_0x69.html | 91 ++ ChartDemo/Doc/html/functions_func_0x6e.html | 68 + ChartDemo/Doc/html/functions_func_0x6f.html | 101 ++ ChartDemo/Doc/html/functions_func_0x70.html | 68 + ChartDemo/Doc/html/functions_func_0x72.html | 97 ++ ChartDemo/Doc/html/functions_func_0x73.html | 236 ++++ ChartDemo/Doc/html/functions_func_0x75.html | 74 + ChartDemo/Doc/html/functions_func_0x76.html | 73 + ChartDemo/Doc/html/functions_func_0x78.html | 66 + ChartDemo/Doc/html/functions_func_0x79.html | 66 + ChartDemo/Doc/html/functions_func_0x7e.html | 106 ++ ChartDemo/Doc/html/functions_vars.html | 171 +++ ChartDemo/Doc/html/hierarchy.html | 95 ++ ChartDemo/Doc/html/index.html | 26 + ChartDemo/Doc/html/pages.html | 28 + ChartDemo/Doc/html/resource_8h-source.html | 103 ++ ...oints_array_1_1_s_chart_point-members.html | 33 + ..._chart_points_array_1_1_s_chart_point.html | 54 + ...uct_s_chart_candlestick_point-members.html | 45 + .../struct_s_chart_candlestick_point.html | 93 ++ .../struct_s_chart_gantt_point-members.html | 43 + .../Doc/html/struct_s_chart_gantt_point.html | 90 ++ .../struct_s_chart_x_y_point-members.html | 43 + .../Doc/html/struct_s_chart_x_y_point.html | 79 ++ ChartDemo/Doc/html/tab_b.gif | Bin 0 -> 35 bytes ChartDemo/Doc/html/tab_l.gif | Bin 0 -> 706 bytes ChartDemo/Doc/html/tab_r.gif | Bin 0 -> 2585 bytes ChartDemo/Doc/html/tabs.css | 105 ++ ChartDemo/LinePropDialog.cpp | 63 + ChartDemo/LinePropDialog.h | 48 + ChartDemo/PointsPropDialog.cpp | 73 + ChartDemo/PointsPropDialog.h | 50 + ChartDemo/SeriesPropDlg.cpp | 204 +++ ChartDemo/SeriesPropDlg.h | 85 ++ ChartDemo/StdAfx.cpp | 8 + ChartDemo/StdAfx.h | 28 + ChartDemo/SurfacePropDialog.cpp | 62 + ChartDemo/SurfacePropDialog.h | 48 + ChartDemo/res/ChartDemo.ico | Bin 0 -> 1078 bytes ChartDemo/res/ChartDemo.rc2 | 13 + ChartDemo/resource.h | 76 ++ README.MD | 32 + pic1.jpg | Bin 0 -> 193876 bytes pic2.jpg | Bin 0 -> 186281 bytes 274 files changed, 37810 insertions(+) create mode 100644 ChartDemo.exe create mode 100644 ChartDemo/ChartCtrl/ChartAxis.cpp create mode 100644 ChartDemo/ChartCtrl/ChartAxis.h create mode 100644 ChartDemo/ChartCtrl/ChartAxisLabel.cpp create mode 100644 ChartDemo/ChartCtrl/ChartAxisLabel.h create mode 100644 ChartDemo/ChartCtrl/ChartBalloonLabel.h create mode 100644 ChartDemo/ChartCtrl/ChartBalloonLabel.inl create mode 100644 ChartDemo/ChartCtrl/ChartBarSerie.cpp create mode 100644 ChartDemo/ChartCtrl/ChartBarSerie.h create mode 100644 ChartDemo/ChartCtrl/ChartCandlestickSerie.cpp create mode 100644 ChartDemo/ChartCtrl/ChartCandlestickSerie.h create mode 100644 ChartDemo/ChartCtrl/ChartCrossHairCursor.cpp create mode 100644 ChartDemo/ChartCtrl/ChartCrossHairCursor.h create mode 100644 ChartDemo/ChartCtrl/ChartCtrl.cpp create mode 100644 ChartDemo/ChartCtrl/ChartCtrl.h create mode 100644 ChartDemo/ChartCtrl/ChartCtrl_source.zip create mode 100644 ChartDemo/ChartCtrl/ChartCursor.cpp create mode 100644 ChartDemo/ChartCtrl/ChartCursor.h create mode 100644 ChartDemo/ChartCtrl/ChartDateTimeAxis.cpp create mode 100644 ChartDemo/ChartCtrl/ChartDateTimeAxis.h create mode 100644 ChartDemo/ChartCtrl/ChartDragLineCursor.cpp create mode 100644 ChartDemo/ChartCtrl/ChartDragLineCursor.h create mode 100644 ChartDemo/ChartCtrl/ChartFont.cpp create mode 100644 ChartDemo/ChartCtrl/ChartFont.h create mode 100644 ChartDemo/ChartCtrl/ChartGanttSerie.cpp create mode 100644 ChartDemo/ChartCtrl/ChartGanttSerie.h create mode 100644 ChartDemo/ChartCtrl/ChartGradient.cpp create mode 100644 ChartDemo/ChartCtrl/ChartGradient.h create mode 100644 ChartDemo/ChartCtrl/ChartGrid.cpp create mode 100644 ChartDemo/ChartCtrl/ChartGrid.h create mode 100644 ChartDemo/ChartCtrl/ChartLabel.h create mode 100644 ChartDemo/ChartCtrl/ChartLabel.inl create mode 100644 ChartDemo/ChartCtrl/ChartLegend.cpp create mode 100644 ChartDemo/ChartCtrl/ChartLegend.h create mode 100644 ChartDemo/ChartCtrl/ChartLineSerie.cpp create mode 100644 ChartDemo/ChartCtrl/ChartLineSerie.h create mode 100644 ChartDemo/ChartCtrl/ChartLogarithmicAxis.cpp create mode 100644 ChartDemo/ChartCtrl/ChartLogarithmicAxis.h create mode 100644 ChartDemo/ChartCtrl/ChartMouseListener.h create mode 100644 ChartDemo/ChartCtrl/ChartPointsArray.h create mode 100644 ChartDemo/ChartCtrl/ChartPointsArray.inl create mode 100644 ChartDemo/ChartCtrl/ChartPointsSerie.cpp create mode 100644 ChartDemo/ChartCtrl/ChartPointsSerie.h create mode 100644 ChartDemo/ChartCtrl/ChartScrollBar.cpp create mode 100644 ChartDemo/ChartCtrl/ChartScrollBar.h create mode 100644 ChartDemo/ChartCtrl/ChartSerie.cpp create mode 100644 ChartDemo/ChartCtrl/ChartSerie.h create mode 100644 ChartDemo/ChartCtrl/ChartSerieBase.h create mode 100644 ChartDemo/ChartCtrl/ChartSerieBase.inl create mode 100644 ChartDemo/ChartCtrl/ChartSeriesMouseListener.h create mode 100644 ChartDemo/ChartCtrl/ChartStandardAxis.cpp create mode 100644 ChartDemo/ChartCtrl/ChartStandardAxis.h create mode 100644 ChartDemo/ChartCtrl/ChartString.h create mode 100644 ChartDemo/ChartCtrl/ChartSurfaceSerie.cpp create mode 100644 ChartDemo/ChartCtrl/ChartSurfaceSerie.h create mode 100644 ChartDemo/ChartCtrl/ChartTitle.cpp create mode 100644 ChartDemo/ChartCtrl/ChartTitle.h create mode 100644 ChartDemo/ChartCtrl/ChartXYSerie.cpp create mode 100644 ChartDemo/ChartCtrl/ChartXYSerie.h create mode 100644 ChartDemo/ChartCtrl/PointsOrdering.h create mode 100644 ChartDemo/ChartDemo.cpp create mode 100644 ChartDemo/ChartDemo.dsp create mode 100644 ChartDemo/ChartDemo.dsw create mode 100644 ChartDemo/ChartDemo.h create mode 100644 ChartDemo/ChartDemo.rc create mode 100644 ChartDemo/ChartDemo.sln create mode 100644 ChartDemo/ChartDemo.vcproj create mode 100644 ChartDemo/ChartDemoDlg.cpp create mode 100644 ChartDemo/ChartDemoDlg.h create mode 100644 ChartDemo/ColourPicker/ColourPicker.cpp create mode 100644 ChartDemo/ColourPicker/ColourPicker.h create mode 100644 ChartDemo/ColourPicker/ColourPopup.cpp create mode 100644 ChartDemo/ColourPicker/ColourPopup.h create mode 100644 ChartDemo/Doc/html/_chart_axis_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_axis_label_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_axis_old_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_balloon_label_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_bar_serie_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_candlestick_serie_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_cross_hair_cursor_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_ctrl_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_cursor_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_date_time_axis_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_demo_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_demo_dlg_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_drag_line_cursor_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_font_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_gantt_serie_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_gradient_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_grid_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_label_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_legend_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_line_serie_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_logarithmic_axis_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_mouse_listener_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_object_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_point_label_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_points_array_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_points_serie_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_scroll_bar_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_serie_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_serie_base_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_series_mouse_listener_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_standard_axis_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_string_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_surface_serie_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_title_8h-source.html create mode 100644 ChartDemo/Doc/html/_chart_x_y_serie_8h-source.html create mode 100644 ChartDemo/Doc/html/_colour_picker_8h-source.html create mode 100644 ChartDemo/Doc/html/_colour_popup_8h-source.html create mode 100644 ChartDemo/Doc/html/_line_prop_dialog_8h-source.html create mode 100644 ChartDemo/Doc/html/_points_ordering_8h-source.html create mode 100644 ChartDemo/Doc/html/_points_prop_dialog_8h-source.html create mode 100644 ChartDemo/Doc/html/_series_prop_dlg_8h-source.html create mode 100644 ChartDemo/Doc/html/_std_afx_8h-source.html create mode 100644 ChartDemo/Doc/html/_surface_prop_dialog_8h-source.html create mode 100644 ChartDemo/Doc/html/annotated.html create mode 100644 ChartDemo/Doc/html/class_c_chart_axis-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_axis.html create mode 100644 ChartDemo/Doc/html/class_c_chart_axis.png create mode 100644 ChartDemo/Doc/html/class_c_chart_axis_label-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_axis_label.html create mode 100644 ChartDemo/Doc/html/class_c_chart_balloon_label-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_balloon_label.html create mode 100644 ChartDemo/Doc/html/class_c_chart_balloon_label.png create mode 100644 ChartDemo/Doc/html/class_c_chart_bar_serie-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_bar_serie.html create mode 100644 ChartDemo/Doc/html/class_c_chart_bar_serie.png create mode 100644 ChartDemo/Doc/html/class_c_chart_candlestick_serie-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_candlestick_serie.html create mode 100644 ChartDemo/Doc/html/class_c_chart_candlestick_serie.png create mode 100644 ChartDemo/Doc/html/class_c_chart_cross_hair_cursor-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_cross_hair_cursor.html create mode 100644 ChartDemo/Doc/html/class_c_chart_cross_hair_cursor.png create mode 100644 ChartDemo/Doc/html/class_c_chart_ctrl-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_ctrl.html create mode 100644 ChartDemo/Doc/html/class_c_chart_cursor-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_cursor.html create mode 100644 ChartDemo/Doc/html/class_c_chart_cursor.png create mode 100644 ChartDemo/Doc/html/class_c_chart_cursor_listener-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_cursor_listener.html create mode 100644 ChartDemo/Doc/html/class_c_chart_date_time_axis-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_date_time_axis.html create mode 100644 ChartDemo/Doc/html/class_c_chart_date_time_axis.png create mode 100644 ChartDemo/Doc/html/class_c_chart_drag_line_cursor-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_drag_line_cursor.html create mode 100644 ChartDemo/Doc/html/class_c_chart_drag_line_cursor.png create mode 100644 ChartDemo/Doc/html/class_c_chart_font-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_font.html create mode 100644 ChartDemo/Doc/html/class_c_chart_gantt_serie-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_gantt_serie.html create mode 100644 ChartDemo/Doc/html/class_c_chart_gantt_serie.png create mode 100644 ChartDemo/Doc/html/class_c_chart_gradient-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_gradient.html create mode 100644 ChartDemo/Doc/html/class_c_chart_grid-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_grid.html create mode 100644 ChartDemo/Doc/html/class_c_chart_label-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_label.html create mode 100644 ChartDemo/Doc/html/class_c_chart_label.png create mode 100644 ChartDemo/Doc/html/class_c_chart_label_provider-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_label_provider.html create mode 100644 ChartDemo/Doc/html/class_c_chart_legend-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_legend.html create mode 100644 ChartDemo/Doc/html/class_c_chart_line_serie-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_line_serie.html create mode 100644 ChartDemo/Doc/html/class_c_chart_line_serie.png create mode 100644 ChartDemo/Doc/html/class_c_chart_logarithmic_axis-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_logarithmic_axis.html create mode 100644 ChartDemo/Doc/html/class_c_chart_logarithmic_axis.png create mode 100644 ChartDemo/Doc/html/class_c_chart_mouse_listener-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_mouse_listener.html create mode 100644 ChartDemo/Doc/html/class_c_chart_points_array-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_points_array.html create mode 100644 ChartDemo/Doc/html/class_c_chart_points_serie-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_points_serie.html create mode 100644 ChartDemo/Doc/html/class_c_chart_points_serie.png create mode 100644 ChartDemo/Doc/html/class_c_chart_scroll_bar-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_scroll_bar.html create mode 100644 ChartDemo/Doc/html/class_c_chart_serie-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_serie.html create mode 100644 ChartDemo/Doc/html/class_c_chart_serie.png create mode 100644 ChartDemo/Doc/html/class_c_chart_serie_base-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_serie_base.html create mode 100644 ChartDemo/Doc/html/class_c_chart_serie_base.png create mode 100644 ChartDemo/Doc/html/class_c_chart_series_mouse_listener-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_series_mouse_listener.html create mode 100644 ChartDemo/Doc/html/class_c_chart_standard_axis-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_standard_axis.html create mode 100644 ChartDemo/Doc/html/class_c_chart_standard_axis.png create mode 100644 ChartDemo/Doc/html/class_c_chart_surface_serie-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_surface_serie.html create mode 100644 ChartDemo/Doc/html/class_c_chart_surface_serie.png create mode 100644 ChartDemo/Doc/html/class_c_chart_title-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_title.html create mode 100644 ChartDemo/Doc/html/class_c_chart_x_y_serie-members.html create mode 100644 ChartDemo/Doc/html/class_c_chart_x_y_serie.html create mode 100644 ChartDemo/Doc/html/class_c_chart_x_y_serie.png create mode 100644 ChartDemo/Doc/html/classes.html create mode 100644 ChartDemo/Doc/html/deprecated.html create mode 100644 ChartDemo/Doc/html/doxygen.css create mode 100644 ChartDemo/Doc/html/doxygen.png create mode 100644 ChartDemo/Doc/html/files.html create mode 100644 ChartDemo/Doc/html/functions.html create mode 100644 ChartDemo/Doc/html/functions_0x63.html create mode 100644 ChartDemo/Doc/html/functions_0x64.html create mode 100644 ChartDemo/Doc/html/functions_0x65.html create mode 100644 ChartDemo/Doc/html/functions_0x66.html create mode 100644 ChartDemo/Doc/html/functions_0x67.html create mode 100644 ChartDemo/Doc/html/functions_0x68.html create mode 100644 ChartDemo/Doc/html/functions_0x69.html create mode 100644 ChartDemo/Doc/html/functions_0x6c.html create mode 100644 ChartDemo/Doc/html/functions_0x6d.html create mode 100644 ChartDemo/Doc/html/functions_0x6e.html create mode 100644 ChartDemo/Doc/html/functions_0x6f.html create mode 100644 ChartDemo/Doc/html/functions_0x70.html create mode 100644 ChartDemo/Doc/html/functions_0x72.html create mode 100644 ChartDemo/Doc/html/functions_0x73.html create mode 100644 ChartDemo/Doc/html/functions_0x74.html create mode 100644 ChartDemo/Doc/html/functions_0x75.html create mode 100644 ChartDemo/Doc/html/functions_0x76.html create mode 100644 ChartDemo/Doc/html/functions_0x78.html create mode 100644 ChartDemo/Doc/html/functions_0x79.html create mode 100644 ChartDemo/Doc/html/functions_0x7e.html create mode 100644 ChartDemo/Doc/html/functions_enum.html create mode 100644 ChartDemo/Doc/html/functions_eval.html create mode 100644 ChartDemo/Doc/html/functions_func.html create mode 100644 ChartDemo/Doc/html/functions_func_0x63.html create mode 100644 ChartDemo/Doc/html/functions_func_0x64.html create mode 100644 ChartDemo/Doc/html/functions_func_0x65.html create mode 100644 ChartDemo/Doc/html/functions_func_0x67.html create mode 100644 ChartDemo/Doc/html/functions_func_0x69.html create mode 100644 ChartDemo/Doc/html/functions_func_0x6e.html create mode 100644 ChartDemo/Doc/html/functions_func_0x6f.html create mode 100644 ChartDemo/Doc/html/functions_func_0x70.html create mode 100644 ChartDemo/Doc/html/functions_func_0x72.html create mode 100644 ChartDemo/Doc/html/functions_func_0x73.html create mode 100644 ChartDemo/Doc/html/functions_func_0x75.html create mode 100644 ChartDemo/Doc/html/functions_func_0x76.html create mode 100644 ChartDemo/Doc/html/functions_func_0x78.html create mode 100644 ChartDemo/Doc/html/functions_func_0x79.html create mode 100644 ChartDemo/Doc/html/functions_func_0x7e.html create mode 100644 ChartDemo/Doc/html/functions_vars.html create mode 100644 ChartDemo/Doc/html/hierarchy.html create mode 100644 ChartDemo/Doc/html/index.html create mode 100644 ChartDemo/Doc/html/pages.html create mode 100644 ChartDemo/Doc/html/resource_8h-source.html create mode 100644 ChartDemo/Doc/html/struct_c_chart_points_array_1_1_s_chart_point-members.html create mode 100644 ChartDemo/Doc/html/struct_c_chart_points_array_1_1_s_chart_point.html create mode 100644 ChartDemo/Doc/html/struct_s_chart_candlestick_point-members.html create mode 100644 ChartDemo/Doc/html/struct_s_chart_candlestick_point.html create mode 100644 ChartDemo/Doc/html/struct_s_chart_gantt_point-members.html create mode 100644 ChartDemo/Doc/html/struct_s_chart_gantt_point.html create mode 100644 ChartDemo/Doc/html/struct_s_chart_x_y_point-members.html create mode 100644 ChartDemo/Doc/html/struct_s_chart_x_y_point.html create mode 100644 ChartDemo/Doc/html/tab_b.gif create mode 100644 ChartDemo/Doc/html/tab_l.gif create mode 100644 ChartDemo/Doc/html/tab_r.gif create mode 100644 ChartDemo/Doc/html/tabs.css create mode 100644 ChartDemo/LinePropDialog.cpp create mode 100644 ChartDemo/LinePropDialog.h create mode 100644 ChartDemo/PointsPropDialog.cpp create mode 100644 ChartDemo/PointsPropDialog.h create mode 100644 ChartDemo/SeriesPropDlg.cpp create mode 100644 ChartDemo/SeriesPropDlg.h create mode 100644 ChartDemo/StdAfx.cpp create mode 100644 ChartDemo/StdAfx.h create mode 100644 ChartDemo/SurfacePropDialog.cpp create mode 100644 ChartDemo/SurfacePropDialog.h create mode 100644 ChartDemo/res/ChartDemo.ico create mode 100644 ChartDemo/res/ChartDemo.rc2 create mode 100644 ChartDemo/resource.h create mode 100644 README.MD create mode 100644 pic1.jpg create mode 100644 pic2.jpg diff --git a/ChartDemo.exe b/ChartDemo.exe new file mode 100644 index 0000000000000000000000000000000000000000..1d12f779883c1cee97e9d03b0dabcad95d368bd4 GIT binary patch literal 114688 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 z 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 + +using namespace std; + +CChartAxis::CChartAxis() + : m_pParentCtrl(NULL), m_bIsHorizontal(true), m_bIsInverted(false), + m_AutoMode(NotAutomatic), m_bIsVisible(true), m_bIsSecondary(false), + m_MaxValue(0), m_MinValue(0), m_UnzoomMax(0), m_UnzoomMin(0), + m_bAutoTicks(true), m_bDiscrete(false),m_StartPos(0), m_EndPos(0), + m_nFontSize(80), m_strFontName(_T("Microsoft Sans Serif")), m_TextColor(0), + m_bAutoMargin(true), m_iMarginSize(0), m_bZoomEnabled(true), + m_dZoomLimit(0.001), m_pScrollBar(NULL), m_AxisColor(RGB(0,0,0)) +{ + m_pAxisGrid = new CChartGrid(); + m_pAxisLabel = new CChartAxisLabel(); +} + +CChartAxis::~CChartAxis() +{ + if (m_pAxisGrid) + { + delete m_pAxisGrid; + m_pAxisGrid = NULL; + } + if (m_pAxisLabel) + { + delete m_pAxisLabel; + m_pAxisLabel = NULL; + } + + if (m_pScrollBar) + { + delete m_pScrollBar; + m_pScrollBar = NULL; + } +} + + +int CChartAxis::GetPosition() +{ + if (m_bIsHorizontal) + { + if (m_bIsSecondary) + return 0; + else + return 100; + } + else + { + if (m_bIsSecondary) + return 100; + else + return 0; + } +} + +void CChartAxis::SetParent(CChartCtrl* pParent) +{ + m_pParentCtrl = pParent; + m_pAxisGrid->m_pParentCtrl = pParent; + m_pAxisLabel->m_pParentCtrl = pParent; +} + +void CChartAxis::SetHorizontal(bool bHorizontal) +{ + m_bIsHorizontal = bHorizontal; + m_pAxisGrid->m_bIsHorizontal = bHorizontal; + m_pAxisLabel->SetHorizontal(bHorizontal); +} + +void CChartAxis::Draw(CDC *pDC) +{ + if (!m_bIsVisible) + return; + if (pDC->GetSafeHdc() == NULL) + return; + + // Initialize the different GDI objects + CPen SolidPen(PS_SOLID,0,m_AxisColor); + CFont NewFont; + NewFont.CreatePointFont(m_nFontSize,m_strFontName.c_str(),pDC) ; + CPen* pOldPen = pDC->SelectObject(&SolidPen); + CFont* pOldFont = pDC->SelectObject(&NewFont); + COLORREF OldTextColor = pDC->SetTextColor(m_TextColor); + int iPrevMode = pDC->SetBkMode(TRANSPARENT); + + // Draw the axis line + int Pos = 0; + if (m_bIsHorizontal) + { + if (!m_bIsSecondary) + Pos = m_AxisRect.top+1; + else + Pos = m_AxisRect.bottom-1; + pDC->MoveTo(m_StartPos,Pos); + pDC->LineTo(m_EndPos,Pos); + } + else + { + if (!m_bIsSecondary) + Pos = m_AxisRect.right-1; + else + Pos = m_AxisRect.left+1; + pDC->MoveTo(Pos,m_StartPos); + pDC->LineTo(Pos,m_EndPos); + } + + // Draw the label + DrawLabel(pDC); + // Clear the ticks on the grid + m_pAxisGrid->ClearTicks(); + + // Now draw all the ticks and their label. + if (m_MaxValue == m_MinValue) + DrawTick(pDC,m_MinValue); + else + { + double TickValue = GetFirstTickValue(); + do + { + DrawTick(pDC,TickValue); + } while (GetNextTickValue(TickValue, TickValue)); + } + + // Draw the grid. + m_pAxisGrid->Draw(pDC); + + // Reset the GDI objects + pDC->SelectObject(pOldPen); + SolidPen.DeleteObject(); + pDC->SelectObject(pOldFont); + NewFont.DeleteObject(); + pDC->SetTextColor(OldTextColor); + pDC->SetBkMode(iPrevMode); +} + +void CChartAxis::DrawTick(CDC* pDC, + double dTickVal) +{ + long TickPos = GetTickPos(dTickVal); + long lLabelPos = ValueToScreen(dTickVal); + TChartString strBuffer = GetTickLabel(dTickVal); + CSize TextSize = pDC->GetTextExtent(strBuffer.c_str()); + CSize LabelSize = m_pAxisLabel->GetSize(pDC); + + bool bLabelOnAxis = IsLabelOnAxis(dTickVal); + bool bTickOnAxis = true; + if (m_bIsHorizontal) + { + if (TickPosm_EndPos) + bTickOnAxis = false; + if (!m_bIsSecondary) + { + if (bTickOnAxis) + { + pDC->MoveTo(TickPos,m_AxisRect.top+1); + pDC->LineTo(TickPos,m_AxisRect.top+4); + } + if (bLabelOnAxis) + { + pDC->ExtTextOut(lLabelPos-TextSize.cx/2,m_AxisRect.top+5, + ETO_CLIPPED|ETO_OPAQUE,NULL,strBuffer.c_str(),NULL); + } + } + else + { + if (bTickOnAxis) + { + pDC->MoveTo(TickPos,m_AxisRect.bottom-1); + pDC->LineTo(TickPos,m_AxisRect.bottom-4); + } + if (bLabelOnAxis) + { + pDC->ExtTextOut(lLabelPos-TextSize.cx/2,m_AxisRect.bottom-5-TextSize.cy, + ETO_CLIPPED|ETO_OPAQUE,NULL,strBuffer.c_str(),NULL); + } + } + } + else + { + if (TickPos>m_StartPos || TickPosMoveTo(m_AxisRect.right-1,TickPos); + pDC->LineTo(m_AxisRect.right-4,TickPos); + } + if (bLabelOnAxis) + { + pDC->ExtTextOut(m_AxisRect.left+LabelSize.cx+4,lLabelPos-TextSize.cy/2, + ETO_CLIPPED|ETO_OPAQUE,NULL,strBuffer.c_str(),NULL); + } + } + else + { + if (bTickOnAxis) + { + pDC->MoveTo(m_AxisRect.left+1,TickPos); + pDC->LineTo(m_AxisRect.left+4,TickPos); + } + if (bLabelOnAxis) + { + pDC->ExtTextOut(m_AxisRect.left+6,lLabelPos-TextSize.cy/2, + ETO_CLIPPED|ETO_OPAQUE,NULL,strBuffer.c_str(),NULL); + } + } + } + m_pAxisGrid->AddTick(TickPos); +} + +bool CChartAxis::IsLabelOnAxis(double TickVal) +{ + long lLabelPos = ValueToScreen(TickVal); + bool bLabelOnAxis = true; + if (m_bIsHorizontal) + { + if (lLabelPosm_EndPos) + bLabelOnAxis = false; + } + else + { + if (lLabelPos>m_StartPos || lLabelPosGetSize(pDC); + int HalfAxisPos = (int)fabs((m_EndPos + m_StartPos)/2.0); + int XPos = 0; + int YPos = 0; + if (m_bIsHorizontal) + { + if (!m_bIsSecondary) + { + CSize TextSize = GetLargestTick(pDC); + YPos = m_AxisRect.top + TextSize.cy + 2; + XPos = HalfAxisPos - LabelSize.cx/2; + } + else + { + YPos = m_AxisRect.top + 0; + XPos = HalfAxisPos - LabelSize.cx/2; + } + } + else + { + if (!m_bIsSecondary) + { + YPos = HalfAxisPos + LabelSize.cy/2; + XPos = m_AxisRect.left + 0; + } + else + { + YPos = HalfAxisPos + LabelSize.cy/2; + XPos = m_AxisRect.right - LabelSize.cx - 2; + } + } + m_pAxisLabel->SetPosition(XPos,YPos,pDC); + m_pAxisLabel->Draw(pDC); +} + +CSize CChartAxis::GetLargestTick(CDC* pDC) +{ + CFont NewFont; + NewFont.CreatePointFont(m_nFontSize,m_strFontName.c_str(),pDC); + CFont* pOldFont = pDC->SelectObject(&NewFont); + + CSize MaxSize(0,0); + if (m_MaxValue == m_MinValue) + { + TChartString strLabel = GetTickLabel(m_MinValue); + MaxSize = pDC->GetTextExtent(strLabel.c_str(),strLabel.size()); + } + else + { + double TickValue = GetFirstTickValue(); + do + { + if (IsLabelOnAxis(TickValue)) + { + TChartString strLabel = GetTickLabel(TickValue); + CSize TextSize = pDC->GetTextExtent(strLabel.c_str(),strLabel.size()); + if (TextSize.cy > MaxSize.cy) + MaxSize.cy = TextSize.cy; + if (TextSize.cx > MaxSize.cx) + MaxSize.cx = TextSize.cx; + } + } while (GetNextTickValue(TickValue, TickValue)); + } + + pDC->SelectObject(pOldFont); + NewFont.DeleteObject(); + return MaxSize; +} + +void CChartAxis::SetInverted(bool bInverted) +{ + m_bIsInverted = bInverted; + RefreshScrollBar(); + m_pParentCtrl->RefreshCtrl(); +} + +void CChartAxis::SetAutomatic(bool bAutomatic) +{ +// m_bIsAutomatic = bAutomatic; + if (bAutomatic) + { + m_AutoMode = FullAutomatic; + m_MinValue = m_MaxValue = 0; + } + else + m_AutoMode = NotAutomatic; + + if (RefreshAutoAxis()) + m_pParentCtrl->RefreshCtrl(); +} + +void CChartAxis::SetAutomaticMode(EAxisAutoModes AutoMode) +{ + m_AutoMode = AutoMode; + if (m_AutoMode != NotAutomatic) + m_MinValue = m_MaxValue = 0; + + if (RefreshAutoAxis()) + m_pParentCtrl->RefreshCtrl(); +} + +void CChartAxis::SetDiscrete(bool bDiscrete) +{ + m_bDiscrete = bDiscrete; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartAxis::SetMinMax(double Minimum, double Maximum) +{ + ASSERT(Maximum>=Minimum); + + m_MinValue = m_UnzoomMin = Minimum; + m_MaxValue = m_UnzoomMax = Maximum; + RefreshScrollBar(); + m_pParentCtrl->RefreshCtrl(); +} + +void CChartAxis::RegisterSeries(CChartSerie* pSeries) +{ + // First check if the series is already present in the list + SeriesList::iterator iter = m_pRelatedSeries.begin(); + for (iter; iter!=m_pRelatedSeries.end(); iter++) + { + if ( (*iter) == pSeries) + return; + } + + m_pRelatedSeries.push_back(pSeries); +} + +void CChartAxis::UnregisterSeries(CChartSerie* pSeries) +{ + SeriesList::iterator iter = m_pRelatedSeries.begin(); + for (iter; iter!=m_pRelatedSeries.end(); iter++) + { + if ( (*iter) == pSeries) + { + m_pRelatedSeries.erase(iter); + return; + } + } +} + +bool CChartAxis::RefreshAutoAxis() +{ + RefreshScrollBar(); + bool bNeedRefresh = false; + if (m_AutoMode == NotAutomatic) + return bNeedRefresh; + + double SeriesMin = 0; + double SeriesMax = 0; + if (m_AutoMode == FullAutomatic) + GetSeriesMinMax(SeriesMin, SeriesMax); + if (m_AutoMode == ScreenAutomatic) + GetSeriesScreenMinMax(SeriesMin, SeriesMax); + + if ( (SeriesMax!=m_MaxValue) || (SeriesMin!=m_MinValue) ) + SetMinMax(SeriesMin,SeriesMax); + + return bNeedRefresh; +} + +bool CChartAxis::RefreshScreenAutoAxis() +{ + RefreshScrollBar(); + bool bNeedRefresh = false; + if (m_AutoMode != ScreenAutomatic) + return bNeedRefresh; + return RefreshAutoAxis(); +} + +void CChartAxis::GetSeriesMinMax(double& Minimum, double& Maximum) +{ + Minimum = 0; + Maximum = 0; + double TempMin = 0; + double TempMax = 0; + + SeriesList::iterator iter = m_pRelatedSeries.begin(); + if (iter != m_pRelatedSeries.end()) + { + if (m_bIsHorizontal) + (*iter)->GetSerieXMinMax(Minimum,Maximum); + else + (*iter)->GetSerieYMinMax(Minimum,Maximum); + } + + for (iter; iter!=m_pRelatedSeries.end(); iter++) + { + if (m_bIsHorizontal) + (*iter)->GetSerieXMinMax(TempMin,TempMax); + else + (*iter)->GetSerieYMinMax(TempMin,TempMax); + + if (TempMin < Minimum) + Minimum = TempMin; + if (TempMax > Maximum) + Maximum = TempMax; + } +} + +void CChartAxis::GetSeriesScreenMinMax(double& Minimum, double& Maximum) +{ + Minimum = 0; + Maximum = 0; + double TempMin = 0; + double TempMax = 0; + + SeriesList::iterator iter = m_pRelatedSeries.begin(); + if (iter != m_pRelatedSeries.end()) + { + if (m_bIsHorizontal) + (*iter)->GetSerieXScreenMinMax(Minimum,Maximum); + else + (*iter)->GetSerieYScreenMinMax(Minimum,Maximum); + } + + for (iter; iter!=m_pRelatedSeries.end(); iter++) + { + if (m_bIsHorizontal) + (*iter)->GetSerieXScreenMinMax(TempMin,TempMax); + else + (*iter)->GetSerieYScreenMinMax(TempMin,TempMax); + + if (TempMin < Minimum) + Minimum = TempMin; + if (TempMax > Maximum) + Maximum = TempMax; + } +} + +long CChartAxis::ValueToScreen(double Value) const +{ + long Offset = 0; + long retVal = 0; + if (m_MaxValue==m_MinValue) + { + Offset = (int)fabs((m_EndPos-m_StartPos)/2.0); + if (m_bIsHorizontal) + retVal = m_StartPos + Offset; + else + retVal = m_StartPos - Offset; + } + else if (!m_bDiscrete) + retVal = ValueToScreenStandard(Value); + else + retVal = ValueToScreenDiscrete(Value); + + return retVal; +} + +long CChartAxis::ValueToScreenStandard(double Value) const +{ + long Offset = 0; + long retVal = 0; + + Offset = (int)floor( (Value - m_MinValue) * GetAxisLenght()/(m_MaxValue-m_MinValue) ); + if (m_bIsHorizontal) + { + if (!m_bIsInverted) + retVal = (m_StartPos + Offset); + else + retVal = (m_EndPos - Offset); + } + else + { + if (!m_bIsInverted) + retVal = (m_StartPos - Offset); + else + retVal = (m_EndPos + Offset); + } + return retVal; +} + +double CChartAxis::ScreenToValue(long ScreenVal) const +{ + if (m_MaxValue==m_MinValue) + return m_MinValue; + + int AxisOffset = 0; + if (!m_bIsHorizontal) + { + if (m_bIsInverted) + AxisOffset = ScreenVal - m_EndPos; + else + AxisOffset = m_StartPos - ScreenVal; + } + else + { + if (!m_bIsInverted) + AxisOffset = ScreenVal - m_StartPos; + else + AxisOffset = m_EndPos - ScreenVal; + } + + return ( (AxisOffset * 1.0 / GetAxisLenght()*(m_MaxValue-m_MinValue)) + m_MinValue); +} + +void CChartAxis::PanAxis(long PanStart, long PanEnd) +{ + double StartVal = ScreenToValue(PanStart); + double EndVal = ScreenToValue(PanEnd); + + double Shift = StartVal - EndVal; + SetZoomMinMax(m_MinValue+Shift,m_MaxValue+Shift); +} + +void CChartAxis::SetZoomMinMax(double Minimum, double Maximum) +{ + if (!m_bZoomEnabled) + return; + if (m_MinValue == m_MaxValue) + return; + + ASSERT(Maximum>=Minimum); + + m_MinValue = Minimum; + if ( (Maximum - Minimum) < m_dZoomLimit) + m_MaxValue = m_MinValue + m_dZoomLimit; + else + m_MaxValue = Maximum; + RefreshScrollBar(); +} + +long CChartAxis::GetAxisLenght() const +{ + long Length = (long)fabs( (m_EndPos-m_StartPos) * 1.0); + return Length; +} + +void CChartAxis::SetVisible(bool bVisible) +{ + m_bIsVisible = bVisible; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartAxis::CreateScrollBar() +{ + m_pScrollBar = new CChartScrollBar(this); + m_pScrollBar->CreateScrollBar(m_pParentCtrl->GetPlottingRect()); +} + +void CChartAxis::UpdateScrollBarPos() +{ + CRect PlottingRect = m_pParentCtrl->GetPlottingRect(); + PlottingRect.top++; PlottingRect.left++; + + // TODO: check if other toolbars are already present + // on other axes. + CRect Temp; + m_pScrollBar->GetWindowRect(&Temp); + if (m_bIsHorizontal && !m_bIsSecondary) + PlottingRect.top = PlottingRect.bottom - Temp.Height(); + if (!m_bIsHorizontal && !m_bIsSecondary) + PlottingRect.right = PlottingRect.left + Temp.Width(); + if (m_bIsHorizontal && m_bIsSecondary) + PlottingRect.bottom = PlottingRect.top + Temp.Height(); + if (!m_bIsHorizontal && m_bIsSecondary) + PlottingRect.left = PlottingRect.right - Temp.Width(); + + m_pScrollBar->MoveWindow(&PlottingRect); +} + +void CChartAxis::RefreshScrollBar() +{ + if (m_pScrollBar) + m_pScrollBar->Refresh(); +} + +void CChartAxis::SetTextColor(COLORREF NewColor) +{ + m_TextColor = NewColor; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartAxis::SetAxisColor(COLORREF NewColor) +{ + m_AxisColor = NewColor; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartAxis::SetFont(int nPointSize, + const TChartString& strFaceName) +{ + m_nFontSize = nPointSize; + m_strFontName = strFaceName; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartAxis::SetMarginSize(bool bAuto, int iNewSize) +{ + m_bAutoMargin = bAuto; + m_iMarginSize = iNewSize; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartAxis::EnableScrollBar(bool bEnabled) +{ + if (m_pScrollBar) + { + m_pScrollBar->SetEnabled(bEnabled); + if (bEnabled) + m_pScrollBar->ShowWindow(SW_SHOW); + else + m_pScrollBar->ShowWindow(SW_HIDE); + } +} + +void CChartAxis::SetAutoHideScrollBar(bool bAutoHide) +{ + if (m_pScrollBar) + m_pScrollBar->SetAutoHide(bAutoHide); +} + +bool CChartAxis::GetAutoHideScrollBar() const +{ + if (m_pScrollBar) + return (m_pScrollBar->GetAutoHide()); + else + return false; +} + +void CChartAxis::UndoZoom() +{ + SetMinMax(m_UnzoomMin,m_UnzoomMax); +} + +void CChartAxis::SetAxisSize(const CRect& ControlRect, + const CRect& MarginRect) +{ + if (m_bIsHorizontal) + { + m_StartPos = MarginRect.left; + m_EndPos = MarginRect.right; + + if (!m_bIsSecondary) + { + m_AxisRect = ControlRect; + m_AxisRect.top = MarginRect.bottom; + } + else + { + m_AxisRect = ControlRect; + m_AxisRect.bottom = MarginRect.top; + } + } + else + { + m_StartPos = MarginRect.bottom; + m_EndPos = MarginRect.top; + + if (!m_bIsSecondary) + { + m_AxisRect = ControlRect; + m_AxisRect.right = MarginRect.left; + } + else + { + m_AxisRect = ControlRect; + m_AxisRect.left = MarginRect.right; + } + } +} + +int CChartAxis::ClipMargin(CRect ControlRect, CRect& MarginRect,CDC* pDC) +{ + if (!m_bIsVisible) + return 0; + + int Size = 0; + CSize TickSize = GetLargestTick(pDC); + CSize LabelSize = m_pAxisLabel->GetSize(pDC); + + if (m_bIsHorizontal) + { + if (!m_bAutoMargin) + Size = m_iMarginSize; + else + { + Size += 4 + 2; //Space above and under the text + + Size += TickSize.cy; + Size += LabelSize.cy; + + m_iMarginSize = Size; + } + + if (!m_bIsSecondary) + { + ControlRect.bottom -= Size; + ControlRect.right -= TickSize.cx/2+3; + + if (ControlRect.bottom < MarginRect.bottom) + MarginRect.bottom = ControlRect.bottom; + if (ControlRect.right < MarginRect.right) + MarginRect.right = ControlRect.right; + } + else + { + ControlRect.top += Size; + ControlRect.right -= TickSize.cx/2+3; + + if (ControlRect.top > MarginRect.top) + MarginRect.top = ControlRect.top; + if (ControlRect.right < MarginRect.right) + MarginRect.right = ControlRect.right; + } + + } + else + { + if (!m_bAutoMargin) + Size = m_iMarginSize; + else + { + Size += 7 + 1; //Space before and after the text + Tick + + Size += TickSize.cx; + Size += LabelSize.cx + 2; + m_iMarginSize = Size; + } + + if (!m_bIsSecondary) + { + ControlRect.left += Size; + ControlRect.top += TickSize.cy/2+3; + + if (ControlRect.top > MarginRect.top) + MarginRect.top = ControlRect.top; + if (ControlRect.left > MarginRect.left) + MarginRect.left = ControlRect.left; + } + else + { + ControlRect.right -= Size; + ControlRect.top += TickSize.cy/2+3; + + if (ControlRect.top > MarginRect.top) + MarginRect.top = ControlRect.top; + if (ControlRect.right < MarginRect.right) + MarginRect.right = ControlRect.right; + } + } + + return Size; +} + +void CChartAxis::Recalculate() +{ + if (m_bAutoTicks) + RefreshTickIncrement(); + RefreshFirstTick(); +} + +void CChartAxis::GetScrollbarSteps(int& iTotalSteps, + int& iCurrentStep) +{ + double SeriesMin=0, SeriesMax=0; + GetSeriesMinMax(SeriesMin,SeriesMax); + + if ((m_MaxValue-m_MinValue) == 0 || (SeriesMax-SeriesMin)==0 ) + { + iTotalSteps = 1; + iCurrentStep = 1; + } + else + { + double dStep = (m_MaxValue - m_MinValue) / 10.0; + iTotalSteps = (int)ceil((SeriesMax - SeriesMin)/dStep); + iCurrentStep = (int)(iTotalSteps * ((m_MinValue - SeriesMin)/(SeriesMax-SeriesMin))); + } +} + +void CChartAxis::SetAxisToScrollStep(int iPreviousStep, + int iCurrentStep, + bool bScrollInverted) +{ + double dStep = (m_MaxValue - m_MinValue) / 10.0; + double dOffset = (iCurrentStep - iPreviousStep) * dStep; + if (bScrollInverted) + SetZoomMinMax(m_MinValue-dOffset,m_MaxValue-dOffset); + else + SetZoomMinMax(m_MinValue+dOffset,m_MaxValue+dOffset); + m_pParentCtrl->RefreshScreenAutoAxes(); +} + +BOOL CChartAxis::IsPointInside(const CPoint& screenPoint) const +{ + return m_AxisRect.PtInRect(screenPoint); +} diff --git a/ChartDemo/ChartCtrl/ChartAxis.h b/ChartDemo/ChartCtrl/ChartAxis.h new file mode 100644 index 0000000..e96568c --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartAxis.h @@ -0,0 +1,526 @@ +/* + * + * ChartAxis.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#ifndef _CHARTAXIS_H_ +#define _CHARTAXIS_H_ + +#include "ChartScrollBar.h" +#include "ChartString.h" +#include + +#include + +class CChartCtrl; +class CChartGrid; +class CChartSerie; +class CChartAxisLabel; + +//! Base class that takes care of the management of a chart axis. +/** + This class cannot be instanciated but should be overriden in order + to provide the required functionality (this is already done for + standard axis, date/time axis and logarithmic axis).
+ The class provides already a lot of functionalities but delegate the + ticks positioning and labeling to the child classes.
+ By default, the class manages a continues range of double values (which + is the case for standard axis and date/time axis) but in some cases, this + is not valid (for instance, a logarithmic scale). In that case, you should + in addition override some specific functions (e.g. those handling the scrollbar). + Take a look at the CChartLogarithmicAxis class for more details. +**/ +class CChartAxis +{ + friend CChartCtrl; + friend CChartGrid; + friend CChartSerie; + friend CChartScrollBar; + +public: + //! Default constructor + CChartAxis(); + //! Default destructor + virtual ~CChartAxis(); + + //! Retrieves the position (in %) of the axis. + int GetPosition(); + + //! Sets the axis in reverse. + /** + For an inverted axis, the values on the axis are + in decreasing order. + @param bInverted + true if the axis has to be inverted. + **/ + void SetInverted(bool bInverted); + //! Retrieves if the axis is inverted or not. + bool IsInverted() const { return m_bIsInverted; } + + //! Sets the axis in automatic or manual mode. + /** + In automatic mode, the axis min and max will be updated + depending on the series related to this axis. + @param bAutomatic + true if the axis should be automatic. + @deprecated You should use the SetAutomaticType instead. + **/ + void SetAutomatic(bool bAutomatic); + //! Returns true if an automatic mode has been set on this axis. + /** + @deprecated You should use the GetAutomaticType instead. + **/ + bool IsAutomatic() const { return m_AutoMode != NotAutomatic; } + + //! The different modes of automatic modes for an axis. + enum EAxisAutoModes + { + //! The axis min and max values are set manually + NotAutomatic, + //! The axis min and max values of the axis are the min and max values of all series associated with this axis. This corresponds to the "standard" automatic mode that was implemented before version 3.0. + FullAutomatic, + //! The axis min and max values of the axis are the visible min and max values of all series associated with this axis. The end result will then depends on how the other axes are configured. + ScreenAutomatic + }; + + //! Sets the automatic mode of the axis + void SetAutomaticMode(EAxisAutoModes AutoMode); + //! Gets the automatic type of the axis + EAxisAutoModes GetAutomaticMode() const { return m_AutoMode; } + + //! Sets the axis visible/invisible. + void SetVisible(bool bVisible); + //! Retrieves the axis automatic mode. + bool IsVisible() const { return m_bIsVisible; } + + //! Sets the axis min and max values. + /** + This doesn't take into account the real type of the axis, + so double values should be provided. + @param Minimum + The min value of the axis + @param Maximum + The max value of the axis. + **/ + void SetMinMax(double Minimum, double Maximum); + //! Gets the min anx max values of the axis. + void GetMinMax(double& Minimum, double& Maximum) const + { + Minimum = m_MinValue; + Maximum = m_MaxValue; + } + + //! Sets the axis color. + void SetAxisColor(COLORREF NewColor); + //! Sets the tick labels color. + void SetTextColor(COLORREF NewColor); + //! Gets the tick labels color. + COLORREF GetTextColor() const { return m_TextColor; } + //! Sets the tick labels font + /** + @param nPointSize + The font point size + @param strFaceName + The font face name + **/ + void SetFont(int nPointSize, const TChartString& strFaceName); + + //! Retrieves the chart axis label object + CChartAxisLabel* GetLabel() const { return m_pAxisLabel; } + //! Retrieves the chart axis grid object + CChartGrid* GetGrid() const { return m_pAxisGrid; } + + //! Sets the margin size + /** + @param bAuto + Specifies if the margin size is automatic or not. + In automatic mode, the iNewSize parameter is ignored + and the margin size is calculated automatically. + @param iNewSize + The new size of the margin, in manual mode. + **/ + void SetMarginSize(bool bAuto, int iNewSize); + + //! Enable the pan and zoom for this axis. + void SetPanZoomEnabled(bool bEnabled) { m_bZoomEnabled = bEnabled; } + //! Sets the zoom limit. + /** + The zoom limit is the minimum lenght (in values) of the axis. + **/ + void SetZoomLimit(double dLimit) { m_dZoomLimit = dLimit; } + + //! Enables/disables the scroll bar. + void EnableScrollBar(bool bEnabled); + //! Retrieves if the scroll bar is enabled or not. + bool ScrollBarEnabled() const + { + if (m_pScrollBar) + return (m_pScrollBar->GetEnabled()); + else + return false; + } + //! Specifies if the scroll bar is in auto-hide mode. + /** + In auto-hide mode, the scroll bar will be hidden until + you hover the mouse over it. + **/ + void SetAutoHideScrollBar(bool bAutoHide); + //! Retrieves if the scroll bar is in auto-hide mode. + bool GetAutoHideScrollBar() const; + + //! Sets the axis in discrete mode + /** + @param bDiscrete + true if the axis has to be discrete, false otherwise. + In discrete mode, the axis doesn't have a continuous range of values + but only steps which are defined by the tick interval. In this mode, + you won't be able to plot points at a different location that in the + middle of two ticks. For instance, if you have a tick interval of 1.0, + trying to plot a value of 0.9 will display the point at the same position + as if the value was 0.3: it will be displayed in the middle of tick 0.0 and + tick 1.0. +
It is mainly used to display the tick label in the middle of two ticks. + This is for instance nice with date/time axis. + **/ + virtual void SetDiscrete(bool bDiscrete); + + //! Converts a value on the axis to a screen position + /** + The functions takes care of the discrete mode (internally, + it calls ValueToScreenStandard or ValueToScreenDiscrete + depending on the discrete mode). + @param Value + The value to convert + @return the screen position of the value + **/ + long ValueToScreen(double Value) const; + //! Converts a screen position to a value on the axis + /** + The function is implemented for an axis with a standard + behavior (the axis shows a continuous range of doubles). + It is the case for standard axis and date/time axis (date + are converted to doubles internally). Axis that needs a different + behavior should override this function (e.g. a logarithmic axis). + The function does not take care of the discrete mode. + @param ScreenVal + The screen value to convert + @return the double value + **/ + virtual double ScreenToValue(long ScreenVal) const; + + //! Returns true if the axis is horizontal + bool IsHorizontal() const { return m_bIsHorizontal; } + + //! Returns true if a screen point is in the region of the axis. + BOOL IsPointInside(const CPoint& screenPoint) const; + +protected: + //! Returns the first tick value. + /** + This pure virtual function must be implemented for specific + axes type. + **/ + virtual double GetFirstTickValue() const = 0; + //! Retrieves the next tick value after a given tick. + /** + This pure virtual function must be implemented for specific + axes type. + @param dCurrentTick + The value of the current tick + @param dNextTick + The value of the next tick will be stored in this parameter + @return true if there is a next or false when the current tick is the last one. + **/ + virtual bool GetNextTickValue(double dCurrentTick, double& dNextTick) const = 0; + //! Retrieves the screen position of a certain tick. + /** + This pure virtual function must be implemented for specific + axes type. + @param Value + The value of the tick for which we want to retrieve the position + @return + the screen position of the tick + **/ + virtual long GetTickPos(double Value) const = 0; + //! Converts a value on the axis to a screen position. + /** + This function is called internally only when the axis is in + discrete mode. This pure virtual function must be implemented for specific + axes type. + @param Value + The value to convert + @return the screen position of the value + **/ + virtual long ValueToScreenDiscrete(double Value) const = 0; + //! Converts a value on the axis to a screen position. + /** + This function is called internally only when the axis is in + standard mode. This virtual function can be overriden when the + axis doesn't display a continuous range of values (e.g. log axis). + @param Value + The value to convert + @return the screen position of the value + **/ + virtual long ValueToScreenStandard(double Value) const; + + //! Retrieves the label for a specific tick. + /** + This pure virtual function must be implemented for specific + axes type. + @param TickValue + The tick value for which we need to get the label. + @return A TChartString containing the label for the tick. + **/ + virtual TChartString GetTickLabel(double TickValue) const = 0; + + //! Forces a recalculation of the tick increment. + virtual void RefreshTickIncrement() = 0; + //! Forces a recalculation of the first tick value. + virtual void RefreshFirstTick() = 0; + + //! Retrieves the step information related to the scrollbar. + /** + This function can be implemented for specific axis types which + should provide a behavior different than the standard behavior + (for instance log axis). + @param iTotalSteps + Stores the total number of steps for the scrollbar + @param iCurrentStep + Stores the current step index for the scrollbar + **/ + virtual void GetScrollbarSteps(int& iTotalSteps, int& iCurrentStep); + //! Sets the axis to the specified scrollbar step. + /** + This function can be implemented for specific axis types which + should provide a behavior different than the standard behavior + (for instance log axis). + @param iPreviousStep + The previous scroll step. + @param iCurrentStep + The current scroll step to which the axis should be moved. + @param bScrollInverted + Specifies if the scroll is inverted or not. + **/ + virtual void SetAxisToScrollStep(int iPreviousStep, int iCurrentStep, bool bScrollInverted); + + //! Pan the axis + /** + This function can be overriden in case the axis doesn't display + a continuous range of values (e.g. log axis). + @param PanStart + The position of the start of the pan + @param PanEnd + The position of the end of the pan + **/ + virtual void PanAxis(long PanStart, long PanEnd); + //! Sets the min and max values of the axis due to a zoom operation. + virtual void SetZoomMinMax(double Minimum, double Maximum); + //! Reverts the zoom and pan settings. + void UndoZoom(); + + //! Retrieves the lenght (in pixels) of the axis + long GetAxisLenght() const; + //! Retrieves the min and max values for all the series related to this axis + void GetSeriesMinMax(double& Minimum, double& Maximum); + //! Retrieves the screen min and max values for all the series related to this axis + void GetSeriesScreenMinMax(double& Minimum, double& Maximum); + +private: + //! Refresh the axis if it is automatic + /** + @return true if the axis has changed + **/ + bool RefreshAutoAxis(); + //! Refresh the axis if it is automatic for the screen only + /** + @return true if the axis has changed + **/ + bool RefreshScreenAutoAxis(); + + //! Returns the largest tick width and the largest tick heigh. + /** + The function returns a CSize object for which the x value + is the largest width and the y value is the largest height. + They do not necessarily belong to the same tick. + **/ + CSize GetLargestTick(CDC* pDC); + + //! Sets the axis as a secondary axis. + /** + A secondary axis is on top for horizontal axis and on the + right for vertical axis. + **/ + void SetSecondary(bool bSecondary) { m_bIsSecondary = bSecondary; } + //! Returns true if the axis is secondary. + bool IsSecondary() const { return m_bIsSecondary; } + //! Sets the axis to horizontal/vertical + void SetHorizontal(bool bHorizontal); + + //! Draw the axis on the chart + /** + @param pDC + The DC used to draw the axis. + **/ + void Draw(CDC* pDC); + //! Draw the axis label + /** + @param pDC + The DC used to draw the axis. + **/ + void DrawLabel(CDC* pDC); + //! Draw a specific tick on the axis. + /** + @param pDC + The DC used to draw the axis. + @param dTickVal + The tick value. + The tick label will be drawn on the tick or between two ticks + depending if the axis is set as standard or discrete. + **/ + void DrawTick(CDC* pDC, double dTickVal); + //! Check whether a specific label is still on the axis. + /** + @param dTickVal + The tick value. + The function returns false if the label is outside + the axis range (and thus, should not be drawn). + **/ + bool IsLabelOnAxis(double TickVal); + + //! Register a series that is associated with this axis. + /** + This is used when the axis is in automatic mode. + **/ + void RegisterSeries(CChartSerie* pSeries); + //! Unregister a series with this axis. + void UnregisterSeries(CChartSerie* pSeries); + + //! Creates and attach a new scroll bar to the axis + void CreateScrollBar(); + //! Update the scroll bar position depending on the plotting rect. + void UpdateScrollBarPos(); + //! Refreshes the scroll bar. + void RefreshScrollBar(); + + //! Sets the parent charting control. + void SetParent(CChartCtrl* pParent); + + //! Sets the axis size + /** + @param ControlRect + The rectangle of the control + @param MarginRect + The rectangle in which the axis should be contained + **/ + void SetAxisSize(const CRect& ControlRect, const CRect& MarginRect); + //! Removes the margin needed for the axis from the full control rect. + /** + @param ControlRect + The rectangle of the control + @param MarginRect + The rectangle in which the axis should be contained + @param pDC + The CDC used to draw the axis. + **/ + int ClipMargin(CRect ControlRect,CRect& MarginRect,CDC* pDC); + //! Recalculate the axis properties. + /** + This function simply calls RefreshTickIncrement and + RefreshFirstTick. + **/ + void Recalculate(); + +protected: + //! The parent chart control. + CChartCtrl* m_pParentCtrl; + + //! Indicates if this is an horizontal or vertical axis + bool m_bIsHorizontal; + //! Indicates if the axis is inverted + bool m_bIsInverted; + //! Indicates if the axis is automatic +// bool m_bIsAutomatic; + //! Indicates the automatic mode of the axis + EAxisAutoModes m_AutoMode; + + //! Indicates if the axis is visible or not + bool m_bIsVisible; + + //! Specifies if the axis is secondary + /** + The secondary axis is either on the top (for horizontal + axis) or on the right (for vertical axis) of the chart. + **/ + bool m_bIsSecondary; + + //! The axis max value + double m_MaxValue; + //! The axis min value + double m_MinValue; + //! Min value of the axis before it has been zoomed + double m_UnzoomMin; + //! Max value of the axis before it has been zoomed + double m_UnzoomMax; + + //! Specify if the tick increment is manual or automatic + bool m_bAutoTicks; + //! Specify if the axis has to be in discrete mode or not + bool m_bDiscrete; + + //! Start position of the axis (in pixels) + int m_StartPos; + //! End position of the axis (in pixels) + int m_EndPos; + //! The rectangle in which the axis is contained. + CRect m_AxisRect; + +private: + //! The font size used for the axis labels + int m_nFontSize; + //! The font face name used for the axis labels + TChartString m_strFontName; + //! The color used for the axis labels + COLORREF m_TextColor; + //! The color used for the axis line + COLORREF m_AxisColor; + + //! The grid related to this axis + CChartGrid* m_pAxisGrid; + //! The axis label associated with this axis + CChartAxisLabel* m_pAxisLabel; + + typedef std::list SeriesList; + //! List containing pointers to series related to this axis + SeriesList m_pRelatedSeries; + + //! Specify if the margin size is calculated automatically + bool m_bAutoMargin; + //! The margin size, used in manual mode + int m_iMarginSize; + + //! Specifies if the zoom is enabled for this axis + bool m_bZoomEnabled; + //! The zoom limit (axis can't be zoomed under this limit) + double m_dZoomLimit; + + //! The axis scrollbar + CChartScrollBar* m_pScrollBar; +}; + +#endif // _CHARTAXIS_H_ \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartAxisLabel.cpp b/ChartDemo/ChartCtrl/ChartAxisLabel.cpp new file mode 100644 index 0000000..da12574 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartAxisLabel.cpp @@ -0,0 +1,157 @@ +/* + * + * ChartAxisLabel.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * History: + * - 24/08/2007: Bug fix in color of the label (text was always black) + * + * + */ + +#include "stdafx.h" +#include "ChartAxisLabel.h" +#include "ChartCtrl.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CChartAxisLabel::CChartAxisLabel() + : m_pParentCtrl(NULL), m_bIsVisible(true), m_TextColor(RGB(0,0,0)), + m_bIsHorizontal(true), m_Font(), m_strLabelText(_T("")) +{ + m_Font.SetVertical(!m_bIsHorizontal); +} + +CChartAxisLabel::~CChartAxisLabel() +{ +} + +void CChartAxisLabel::SetVisible(bool bVisible) +{ + m_bIsVisible = bVisible; + if (m_pParentCtrl) + m_pParentCtrl->RefreshCtrl(); +} + +void CChartAxisLabel::SetColor(COLORREF NewColor) +{ + m_TextColor = NewColor; + if (m_pParentCtrl) + m_pParentCtrl->RefreshCtrl(); +} + +void CChartAxisLabel::SetText(const TChartString& NewText) +{ + m_strLabelText = NewText; + if (m_pParentCtrl) + m_pParentCtrl->RefreshCtrl(); +} + +void CChartAxisLabel::SetFont(int nPointSize, const TChartString& strFaceName) +{ + m_Font.SetFont(strFaceName, nPointSize); + if (m_pParentCtrl) + m_pParentCtrl->RefreshCtrl(); +} + +void CChartAxisLabel::SetHorizontal(bool bHorizontal) +{ + m_bIsHorizontal = bHorizontal; + m_Font.SetVertical(!m_bIsHorizontal); +} + +void CChartAxisLabel::SetFont(const CChartFont& newFont) +{ + m_Font = newFont; + if (m_pParentCtrl) + m_pParentCtrl->RefreshCtrl(); +} + +CSize CChartAxisLabel::GetSize(CDC *pDC) const +{ + CSize LabelSize; + LabelSize.cx = 0; + LabelSize.cy = 0; + + if (!m_bIsVisible) + return LabelSize; + if (!pDC->GetSafeHdc()) + return LabelSize; + if (m_strLabelText == _T("")) + return LabelSize; + + m_Font.SelectFont(pDC); + + LabelSize = pDC->GetTextExtent(m_strLabelText.c_str()); + LabelSize.cx += 4; + LabelSize.cy += 4; + if (!m_bIsHorizontal) + { + int Width = LabelSize.cy; + int Height = LabelSize.cx; + LabelSize.cx = Width; + LabelSize.cy = Height; + } + m_Font.UnselectFont(pDC); + + return LabelSize; +} + +void CChartAxisLabel::Draw(CDC *pDC) +{ + if (!m_bIsVisible) + return; + if (!pDC->GetSafeHdc()) + return; + if (m_strLabelText == _T("")) + return; + + int iPrevMode = pDC->SetBkMode(TRANSPARENT); + COLORREF OldColor = pDC->SetTextColor(m_TextColor); + + m_Font.SelectFont(pDC); + if (!m_bIsHorizontal) + { + pDC->ExtTextOut(m_TextRect.left + 2,m_TextRect.top, + ETO_CLIPPED,NULL,m_strLabelText.c_str(),NULL); + } + else + { + pDC->ExtTextOut(m_TextRect.left,m_TextRect.top + 2, + ETO_CLIPPED,NULL,m_strLabelText.c_str(),NULL); + } + m_Font.UnselectFont(pDC); + + pDC->SetBkMode(iPrevMode); + pDC->SetTextColor(OldColor); +} + +void CChartAxisLabel::SetPosition(int LeftBorder, int TopBorder, CDC *pDC) +{ + CSize NewSize = GetSize(pDC); + m_TextRect.top = TopBorder; + m_TextRect.bottom = TopBorder + NewSize.cy; + m_TextRect.left = LeftBorder; + m_TextRect.right = LeftBorder + NewSize.cx; +} diff --git a/ChartDemo/ChartCtrl/ChartAxisLabel.h b/ChartDemo/ChartCtrl/ChartAxisLabel.h new file mode 100644 index 0000000..1e420a8 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartAxisLabel.h @@ -0,0 +1,112 @@ +/* + * + * ChartAxisLabel.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#if !defined(AFX_CHARTAXISLABEL_H__0E5519C8_A2F4_4CED_9681_32A56B25D0C5__INCLUDED_) +#define AFX_CHARTAXISLABEL_H__0E5519C8_A2F4_4CED_9681_32A56B25D0C5__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "ChartString.h" +#include "ChartFont.h" + +class CChartCtrl; +class CChartAxis; + +//! Draws the label of an axis +/** + The label axis is displayed under or next to the tick values. + The label is retrieved by calling CChartAxis::GetAxisLabel. +**/ +class CChartAxisLabel +{ + friend CChartAxis; + +public: + //! Sets the text of the axis label. + void SetText(const TChartString& NewText); + //! Retrieves the text of the axis label. + TChartString GetText() const { return m_strLabelText; } + + //! Sets the font of the text. + /** + @param nPointSize + The font point size. + @param strFaceName + The font face name ("Times New Roman", "Arial", ...) + **/ + void SetFont(int nPointSize, const TChartString& strFaceName); + //! Sets the font of the text. + /** + This function allows to set extended font style by passing + a CChartFont object. + @param newFont + The new font. + **/ + void SetFont(const CChartFont& newFont); + + //! Shows/hides the title. + void SetVisible(bool bVisible); + //! Returns true if the title is visible. + bool IsVisible() const { return m_bIsVisible; } + + //! Retrieves the text color. + COLORREF GetColor() const { return m_TextColor; } + //! Sets the text color. + void SetColor(COLORREF NewColor); + +private: + //! Constructor + CChartAxisLabel(); + //! Destructor + virtual ~CChartAxisLabel(); + + //! Sets in horizontal or vertical mode. + void SetHorizontal(bool bHorizontal); + //! Sets the position of the label. + void SetPosition(int LeftBorder, int TopBorder, CDC *pDC); + //! Draws the label. + void Draw(CDC* pDC); + //! Retrieves the size of the label. + CSize GetSize(CDC* pDC) const; + + + //! The parent charting control. + CChartCtrl* m_pParentCtrl; + //! Specifies if the label is visible or not. + bool m_bIsVisible; + + //! The rectangle in which the label is displayed. + CRect m_TextRect; + //! The text color. + COLORREF m_TextColor; + + //! Specifies if the axis is horizontal or not. + bool m_bIsHorizontal; + //! The font used for the text label. + CChartFont m_Font; + + //! The string to display for the label. + TChartString m_strLabelText; +}; + +#endif // !defined(AFX_CHARTAXISLABEL_H__0E5519C8_A2F4_4CED_9681_32A56B25D0C5__INCLUDED_) diff --git a/ChartDemo/ChartCtrl/ChartBalloonLabel.h b/ChartDemo/ChartCtrl/ChartBalloonLabel.h new file mode 100644 index 0000000..7634bb2 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartBalloonLabel.h @@ -0,0 +1,101 @@ +/* + * + * ChartBalloonLabel.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#ifndef _CHARTBALLOONLABEL_H_ +#define _CHARTBALLOONLABEL_H_ + +#include "ChartLabel.h" +#include "ChartFont.h" + +//! Specialization of the CChartLabel to display a balloon label. +/** + A balloon label is a label with a rounded rectangle area in which the + text is displayed and which is connected with a line to the point to + which it is attached. +**/ +template +class CChartBalloonLabel : public CChartLabel +{ + friend CChartSerieBase; + +public: + //! Sets the background color of the text area. + void SetBackgroundColor(COLORREF colBackground); + //! Retrieves the background color of the text area. + COLORREF GetBackgroundColor() const { return m_colBackground; } + //! Sets the color of the line connecting the point to the text area. + void SetLineColor(COLORREF colArrow); + //! Retrieves the color of the line connecting the point to the text area. + COLORREF GetLineColor() const { return m_colLine; } + //! Sets the color of border's text area. + void SetBorderColor(COLORREF colBorder); + //! Retrieves the color of border's text area. + COLORREF GetBorderColor() const { return m_colBorder; } + + //! Specifies if the text area is rounded or not. + void SetRoundedRect(bool bRounded); + //! Returns true if the text area is rounded. + bool GetRoundedRect() const { return m_bRoundedRect; } + + //! Sets the font of the text. + /** + @param nPointSize + The font point size. + @param strFaceName + The font face name ("Times New Roman", "Arial", ...) + **/ + void SetFont(int nPointSize, const TChartString& strFaceName); + //! Sets the font of the text. + /** + This function allows to set extended font style by passing + a CChartFont object. + @param newFont + The new font. + **/ + void SetFont(const CChartFont& newFont); + + //! Constructor + CChartBalloonLabel(CChartCtrl* pParentCtrl, CChartSerieBase* pParentSeries); + //! Destructor + ~CChartBalloonLabel(); + +protected: + //! Draw the label. + void Draw(CDC* pDC, unsigned uPointIndex); + +private: + //! Color of the liune connecting the point to the text area. + COLORREF m_colLine; + //! Color of the text area's background. + COLORREF m_colBackground; + //! Color of border's text area. + COLORREF m_colBorder; + + //! The font used for the text label. + CChartFont m_Font; + + //! Specifies if the rectangle is rounded or not. + bool m_bRoundedRect; +}; + +#include "ChartBalloonLabel.inl" + +#endif // _CHARTBALLOONLABEL_H_ diff --git a/ChartDemo/ChartCtrl/ChartBalloonLabel.inl b/ChartDemo/ChartCtrl/ChartBalloonLabel.inl new file mode 100644 index 0000000..db49930 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartBalloonLabel.inl @@ -0,0 +1,138 @@ +/* + * + * ChartBalloonLabel.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#include "ChartCtrl.h" +#include "ChartSerie.h" +#include "ChartBalloonLabel.h" + +template +CChartBalloonLabel::CChartBalloonLabel(CChartCtrl* pParentCtrl, + CChartSerieBase* pParentSeries) + : CChartLabel(pParentCtrl, pParentSeries), m_bRoundedRect(true) +{ + m_colBackground = RGB(255,255,225); + m_colLine = RGB(255,255,255); + m_colBorder = RGB(0,0,0); +} + +template +CChartBalloonLabel::~CChartBalloonLabel() +{ +} + +template +void CChartBalloonLabel::SetBackgroundColor(COLORREF colBackground) +{ + m_colBackground = colBackground; + m_pParentCtrl->RefreshCtrl(); +} + +template +void CChartBalloonLabel::SetLineColor(COLORREF colArrow) +{ + m_colLine = colArrow; + m_pParentCtrl->RefreshCtrl(); +} + +template +void CChartBalloonLabel::SetBorderColor(COLORREF colBorder) +{ + m_colBorder = colBorder; + m_pParentCtrl->RefreshCtrl(); +} + +template +void CChartBalloonLabel::SetRoundedRect(bool bRounded) +{ + m_bRoundedRect = bRounded; + m_pParentCtrl->RefreshCtrl(); +} + +template +void CChartBalloonLabel::SetFont(int nPointSize, const TChartString& strFaceName) +{ + m_Font.SetFont(strFaceName, nPointSize); + if (m_pParentCtrl) + m_pParentCtrl->RefreshCtrl(); +} + +template +void CChartBalloonLabel::SetFont(const CChartFont& newFont) +{ + m_Font = newFont; + if (m_pParentCtrl) + m_pParentCtrl->RefreshCtrl(); +} + +template +void CChartBalloonLabel::Draw(CDC* pDC, unsigned uPointIndex) +{ + if (m_pLabelProvider) + { + PointType Point = m_pParentSeries->GetPoint(uPointIndex); + m_strLabelText = m_pLabelProvider->GetText(m_pParentSeries, uPointIndex); + } + if (m_strLabelText == _T("")) + return; + + CPoint screenPt = m_pParentSeries->GetPointScreenCoord(uPointIndex); + + // Create the pen for the arrow + CPen newPen(PS_SOLID, 1, m_colLine); + CPen* pOldPen = pDC->SelectObject(&newPen); + + // Draw first the arrow + pDC->MoveTo(screenPt); + pDC->LineTo(screenPt.x,screenPt.y-20); + + // Create and select a new pen for the border + newPen.DeleteObject(); + newPen.CreatePen(PS_SOLID, 1, m_colBorder); + pDC->SelectObject(&newPen); + m_Font.SelectFont(pDC); + + // Create the brush to fill the rectangle + CBrush newBrush(m_colBackground); + CBrush* pOldBrush = pDC->SelectObject(&newBrush); + + // Calculate the size of the + CSize labelSize = pDC->GetTextExtent(m_strLabelText.c_str()); + labelSize += CSize(10,10); + int x = screenPt.x; + int y = screenPt.y; + CRect labelRect(CPoint(x-labelSize.cx/2,y-19-labelSize.cy),labelSize); + + // Draw the rectangle + if (m_bRoundedRect) + pDC->RoundRect(labelRect,CPoint(10,10)); + else + pDC->Rectangle(labelRect); + + // Draw the text + pDC->TextOut(labelRect.left+5,labelRect.top+5,m_strLabelText.c_str()); + + // Clean the objects + pDC->SelectObject(pOldPen); + pDC->SelectObject(pOldBrush); + newPen.DeleteObject(); + newBrush.DeleteObject(); + m_Font.UnselectFont(pDC); +} \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartBarSerie.cpp b/ChartDemo/ChartCtrl/ChartBarSerie.cpp new file mode 100644 index 0000000..eed94ec --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartBarSerie.cpp @@ -0,0 +1,392 @@ +/* + * + * ChartBarSerie.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#include "stdafx.h" +#include "ChartBarSerie.h" +#include "ChartCtrl.h" +#include + +using namespace std; + +int CChartBarSerie::m_iInterSpace = 0; +std::list CChartBarSerie::m_lstBarSeries; + +CChartBarSerie::CChartBarSerie(CChartCtrl* pParent) + : CChartXYSerie(pParent), m_iBarWidth(20), m_iBorderWidth(1), + m_BorderColor(RGB(0,0,0)), m_uGroupId(0), m_bGradient(true), + m_GradientColor(RGB(255,255,255)), m_GradientType(gtHorizontalDouble), + m_bHorizontal(false), m_dBaseLine(0), m_bAutoBaseLine(true), m_bStacked(false) +{ + m_lstBarSeries.push_back(this); + m_iShadowDepth = 3; + m_bShadow = false; +} + +CChartBarSerie::~CChartBarSerie() +{ + TBarSeriesList::iterator iter = m_lstBarSeries.begin(); + while (iter!=m_lstBarSeries.end()) + { + if ((*iter) == this) + iter = m_lstBarSeries.erase(iter); + else + iter++; + } +} + +void CChartBarSerie::SetHorizontal(bool bHorizontal) +{ + m_bHorizontal = bHorizontal; + if (m_bHorizontal) + SetSeriesOrdering(poYOrdering); + else + SetSeriesOrdering(poXOrdering); + m_pParentCtrl->RefreshCtrl(); +} + +void CChartBarSerie::SetBorderColor(COLORREF BorderColor) +{ + m_BorderColor = BorderColor; + m_pParentCtrl->RefreshCtrl(); +} +void CChartBarSerie::SetBorderWidth(int Width) +{ + m_iBorderWidth = Width; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartBarSerie::SetBarWidth(int Width) +{ + m_iBarWidth = Width; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartBarSerie::SetGroupId(unsigned GroupId) +{ + m_uGroupId = GroupId; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartBarSerie::ShowGradient(bool bShow) +{ + m_bGradient = bShow; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartBarSerie::SetGradient(COLORREF GradientColor, EGradientType GradientType) +{ + m_GradientColor = GradientColor; + m_GradientType = GradientType; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartBarSerie::SetStacked(bool bStacked) +{ + m_bStacked = bStacked; + m_pParentCtrl->RefreshCtrl(); +} + +bool CChartBarSerie::IsStacked() +{ + return m_bStacked; +} + +void CChartBarSerie::DrawBar(CDC* pDC, CBrush* pFillBrush, CBrush* pBorderBrush, + CRect BarRect) +{ + if (m_bShadow) + { + CBrush ShadowBrush(m_ShadowColor); + CRect ShadowRect(BarRect); + ShadowRect.OffsetRect(m_iShadowDepth,m_iShadowDepth); + pDC->FillRect(ShadowRect,&ShadowBrush); + } + pDC->FillRect(BarRect,pBorderBrush); + + CRect FillRect(BarRect); + FillRect.DeflateRect(m_iBorderWidth,m_iBorderWidth); + if (m_bGradient) + { + CChartGradient::DrawGradient(pDC,FillRect,m_SerieColor,m_GradientColor, + m_GradientType); + } + else + { + pDC->FillRect(FillRect,pFillBrush); + } +} + +void CChartBarSerie::Draw(CDC* pDC) +{ + if (!m_bIsVisible) + return; + if (!pDC->GetSafeHdc()) + return; + + RefreshStackedCache(); + int iMinorOffset = GetMinorOffset(); + + CRect TempClipRect(m_PlottingRect); + TempClipRect.DeflateRect(1,1); + pDC->SetBkMode(TRANSPARENT); + pDC->IntersectClipRect(TempClipRect); + + CBrush BorderBrush(m_BorderColor); + CBrush FillBrush(m_SerieColor); + //Draw all points that haven't been drawn yet + for (m_uLastDrawnPoint;m_uLastDrawnPoint<(int)GetPointsCount();m_uLastDrawnPoint++) + { + CRect BarRect = GetBarRectangle(m_uLastDrawnPoint,iMinorOffset); + DrawBar(pDC, &FillBrush, &BorderBrush, BarRect); + } + + pDC->SelectClipRgn(NULL); + DeleteObject(BorderBrush); + DeleteObject(FillBrush); +} + +void CChartBarSerie::DrawAll(CDC *pDC) +{ + if (!m_bIsVisible) + return; + if (!pDC->GetSafeHdc()) + return; + + RefreshStackedCache(); + int iMinorOffset = GetMinorOffset(); + + unsigned uFirst=0, uLast=0; + if (!GetVisiblePoints(uFirst,uLast)) + return; + + CRect TempClipRect(m_PlottingRect); + TempClipRect.DeflateRect(1,1); + if (uFirst>0) + uFirst--; + if (uLastSetBkMode(TRANSPARENT); + pDC->IntersectClipRect(TempClipRect); + + CBrush BorderBrush(m_BorderColor); + CBrush FillBrush(m_SerieColor); + for (m_uLastDrawnPoint=uFirst;m_uLastDrawnPoint<=uLast;m_uLastDrawnPoint++) + { + CRect BarRect = GetBarRectangle(m_uLastDrawnPoint,iMinorOffset); + DrawBar(pDC, &FillBrush, &BorderBrush, BarRect); + } + + pDC->SelectClipRgn(NULL); + DeleteObject(BorderBrush); + DeleteObject(FillBrush); +} + +void CChartBarSerie::DrawLegend(CDC* pDC, const CRect& rectBitmap) const +{ + if (m_strSerieName== _T("")) + return; + + //Draw bar: + CBrush BorderBrush(m_BorderColor); + pDC->FillRect(rectBitmap,&BorderBrush); + + CRect FillRect(rectBitmap); + CBrush FillBrush(m_SerieColor); + FillRect.DeflateRect(m_iBorderWidth,m_iBorderWidth); + if (m_bGradient) + { + CChartGradient::DrawGradient(pDC,FillRect,m_SerieColor,m_GradientColor,m_GradientType); + } + else + { + pDC->FillRect(FillRect,&FillBrush); + } +} + +bool CChartBarSerie::IsPointOnSerie(const CPoint& screenPoint, unsigned& uIndex) const +{ + uIndex = INVALID_POINT; + if (!m_bIsVisible) + return false; + + RefreshStackedCache(); + int iMinorOffset = GetMinorOffset(); + + unsigned uFirst=0, uLast=0; + if (!GetVisiblePoints(uFirst,uLast)) + return false; + + bool bResult = false; + for (unsigned i=uFirst ; i < uLast ; i++) + { + CRect BarRect = GetBarRectangle(i,iMinorOffset); + if (BarRect.PtInRect(screenPoint)) + { + bResult = true; + uIndex = i; + break; + } + } + return bResult; +} + +int CChartBarSerie::GetMinorOffset() const +{ + int iOffset = 0; + int iTotalWidth = 0; + int iLargestStacked = 0; + bool bFound = false; + + TBarSeriesList::const_iterator iter = m_lstBarSeries.begin(); + for (iter; iter!=m_lstBarSeries.end(); iter++) + { + // Skip the series with a different group Id + if ((*iter)->GetGroupId() != m_uGroupId) + continue; + + if ((*iter)->IsStacked() ) + { + if ((*iter)->GetBarWidth() > iLargestStacked) + iLargestStacked = (*iter)->GetBarWidth(); + } + else + { + if (!bFound) + { + if ((*iter)==this) + bFound = true; + else + iOffset += (*iter)->GetBarWidth() + m_iInterSpace; + } + iTotalWidth += (*iter)->GetBarWidth() + m_iInterSpace; + } + } + // Remove the interspace because it has been counted once too much. + iTotalWidth -= m_iInterSpace; + + if (iLargestStacked > 0) + iTotalWidth += iLargestStacked + m_iInterSpace; + + // If this series is a stacked series, it is put at the start + if (m_bStacked) + iOffset = 0; + else if (iLargestStacked > 0) + { + iOffset += iLargestStacked + m_iInterSpace; + } + return (iOffset - iTotalWidth/2); +} + +CRect CChartBarSerie::GetBarRectangle(unsigned uPointIndex, int minorOffset) const +{ + SChartXYPoint point = GetPoint(uPointIndex); + TBarSeriesList::const_iterator iter = m_lstStackedSeries.begin(); + + bool bCalcOffset = false; + if (m_bStacked && (*iter)!=this) + bCalcOffset = true; + + double dXOffset = 0; + double dYOffset = 0; + if (bCalcOffset) + { + for (iter; iter!=m_lstStackedSeries.end(); iter++) + { + if ( (*iter)->GetPointsCount() <= uPointIndex) + continue; + + if ( (*iter) == this) + break; + + dXOffset += (*iter)->GetPoint(uPointIndex).GetX(); + dYOffset += (*iter)->GetPoint(uPointIndex).GetY(); + } + } + + int barXStart, barXEnd, barYStart, barYEnd; + if (m_bHorizontal) + { + if (bCalcOffset) + { + barXStart = m_pHorizontalAxis->ValueToScreen(dXOffset); + barXEnd = m_pHorizontalAxis->ValueToScreen(dXOffset+point.X); + } + else + { + barXEnd = m_pHorizontalAxis->ValueToScreen(point.X); + if (!m_bAutoBaseLine) + barXStart = m_pHorizontalAxis->ValueToScreen(m_dBaseLine); + else + { + double Position = m_pVerticalAxis->GetPosition()/100.00; + barXStart = m_PlottingRect.left + (int)(Position * (m_PlottingRect.right-m_PlottingRect.left)); + } + } + barYStart = m_pVerticalAxis->ValueToScreen(point.Y) + minorOffset; + barYEnd = m_pVerticalAxis->ValueToScreen(point.Y) + minorOffset + m_iBarWidth; + } + else + { + if (bCalcOffset) + { + barYStart = m_pVerticalAxis->ValueToScreen(dYOffset); + barYEnd = m_pVerticalAxis->ValueToScreen(dYOffset+point.Y); + } + else + { + barYEnd = m_pVerticalAxis->ValueToScreen(point.Y); + if (!m_bAutoBaseLine) + barYStart = m_pVerticalAxis->ValueToScreen(m_dBaseLine); + else + { + double Position = m_pHorizontalAxis->GetPosition()/100.00; + barYStart = m_PlottingRect.left + (int)(Position * (m_PlottingRect.bottom-m_PlottingRect.top)); + } + } + barXStart = m_pHorizontalAxis->ValueToScreen(point.X) + minorOffset; + barXEnd = m_pHorizontalAxis->ValueToScreen(point.X) + minorOffset + m_iBarWidth; + } + + CRect barRect(min(barXStart, barXEnd), min(barYStart, barYEnd), + max(barXStart, barXEnd), max(barYStart, barYEnd) ); + return barRect; +} + +void CChartBarSerie::RefreshStackedCache() const +{ + m_lstStackedSeries.clear(); + if (!m_bStacked) + return; + + TBarSeriesList::const_iterator iter = m_lstBarSeries.begin(); + for (iter; iter!=m_lstBarSeries.end(); iter++) + { + // Skip the series with a different group Id + if ((*iter)->GetGroupId() != m_uGroupId) + continue; + + if ((*iter)->IsStacked() ) + { + m_lstStackedSeries.push_back(*iter); + } + } +} diff --git a/ChartDemo/ChartCtrl/ChartBarSerie.h b/ChartDemo/ChartCtrl/ChartBarSerie.h new file mode 100644 index 0000000..5f536b5 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartBarSerie.h @@ -0,0 +1,203 @@ +/* + * + * ChartBarSerie.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#pragma once +#include "ChartXYSerie.h" +#include "ChartGradient.h" +#include + +//! Specialization of a CChartSerie to display a bars series. +/** + This class is a specialized series class used to display vertical (default) + or horizontal bars. Each bar in the series is centered around its X value + (for vertical bars) or Y value (for horizontal bars). Bars can be grouped + together, so that they do not overlap but are stacked next to each other + (or on top of each other). This is done by specifying a group Id: bar series + with the same group Id will be grouped together (stacked). Series with different + group Id will be independant (they will be drawn as if they were the only one, + meaning that the different series will probably overlap). +**/ +class CChartBarSerie : public CChartXYSerie +{ +public: + //! Constructor + CChartBarSerie(CChartCtrl* pParent); + //! Destructor + ~CChartBarSerie(); + + //! Specifies if the bars are vertical or horizontal. + void SetHorizontal(bool bHorizontal); + //! Returns true if bars are horizontal, false otherwise. + bool GetHorizontal() const { return m_bHorizontal; } + + //! Sets the bars border color + void SetBorderColor(COLORREF BorderColor); + //! Returns the bars border color + COLORREF GetBorderColor() const { return m_BorderColor; } + //! Sets the bars border width + void SetBorderWidth(int Width); + //! Returns the bars border width + int GetBorderWidth() const { return m_iBorderWidth; } + //! Sets the bars width (in pixels) + void SetBarWidth(int Width); + //! Returns the bars width (in pixels) + int GetBarWidth() const { return m_iBarWidth; } + + //! Set the group Id of the series + /** + The group Id allows to stack series next to each other (or on top of + each other). + **/ + void SetGroupId(unsigned GroupId); + //! Returns the group Id of the series + unsigned GetGroupId() const { return m_uGroupId; } + + //! Specifies if the series is stacked with other bar series + /** + All bar series with the same group Id and with the stacked + flag to true will be drawn on top of each other (for vertical + bars). + **/ + void SetStacked(bool bStacked); + //! Returns true if the series is stacked + bool IsStacked(); + + //! Specifies if a gradient is applied to the bars + void ShowGradient(bool bShow); + //! Sets the gradient style + /** + @param GradientColor + The second color used for the gradient (the first one being + the original series color). + @param GradientType + The type of gradient used between the two colors (vertical, horizontal, ...) + **/ + void SetGradient(COLORREF GradientColor, EGradientType GradientType); + + //! Static function used to specify the space (in pixels) between series of the same group + static void SetInterSpace(int Space) { m_iInterSpace = Space; } + //! Static function returning the space between series of the same group. + static int GetInterSpace() { return m_iInterSpace; } + + //! Specifies a base line for the bars. + /** + If a baseline is specified, the bars will be drawn between that value + and the point value, instead of being drawn between the axis ans the + point value. + @param bAutomatic + If true, the bars are drawn between the axis and the point value. + @param dBaseLine + The value of the baseline. This parameter is ignored if bAutomatic is true. + **/ + void SetBaseLine(bool bAutomatic, double dBaseLine) + { + m_bAutoBaseLine = bAutomatic; + m_dBaseLine = dBaseLine; + } + + //! Check whether a screen point is on the series. + /** + This function returns true if the screen point is on one of the bars of + the series. In that case, the index of the point is stored in the uIndex + parameter. + @param screenPoint + The screen point to test + @param uIndex + If the point is close to a specific point of the series, its index is stored here. + @return true if the point is on the series + **/ + bool IsPointOnSerie(const CPoint& screenPoint, unsigned& uIndex) const; + +private: + typedef std::list TBarSeriesList; + + //! Draws the legend icon for the series. + /** + This pure virtual function should be overriden by child classes. + @param pDC + The device context used to draw + @param rectBitmap + The rectangle in which to draw the legend icon + **/ + void DrawLegend(CDC* pDC, const CRect& rectBitmap) const; + + //! Draws the most recent points of the series. + /** + This pure virtual function should be overriden by child classes. + This function should only draw the points that were not previously + drawn. + @param pDC + The device context used to draw + **/ + void Draw(CDC* pDC); + //! Redraws the full series. + /** + This pure virtual function should be overriden by child classes. + @param pDC + The device context used to draw + **/ + void DrawAll(CDC *pDC); + + void DrawBar(CDC* pDC, CBrush* pFillBrush, CBrush* pBorderBrush, + CRect BarRect); + + // Retrieves the offset of the serie along the minor axis (horizontal + // axis for vertical bars). This offset is based on series with the + // same group Id. + int GetMinorOffset() const; + CRect GetBarRectangle(unsigned uPointIndex, int minorOffset) const; + + void RefreshStackedCache() const; + + + //! Space between two series of the same group. + static int m_iInterSpace; + //! List of all bar series added to the control + static TBarSeriesList m_lstBarSeries; + + //! Specifies if the bars are horizontal or vertical. + bool m_bHorizontal; + + // The base line specifies the position (in terms of the value + // axis) where the bars start from. If m_bAutoBaseLine is true + // they start from the axis position. + double m_dBaseLine; + bool m_bAutoBaseLine; + + // Specifies to which group this series belongs to. Series in the same group are + // 'stacked' next to each other. + unsigned m_uGroupId; + + int m_iBarWidth; + int m_iBorderWidth; + COLORREF m_BorderColor; + + bool m_bGradient; + COLORREF m_GradientColor; + EGradientType m_GradientType; + + // Specifies if the bar series has to be stacked with other bar + // series with the same group Id + bool m_bStacked; + + // Cache of the stacked series with the same group Id as this series. + mutable TBarSeriesList m_lstStackedSeries; +}; diff --git a/ChartDemo/ChartCtrl/ChartCandlestickSerie.cpp b/ChartDemo/ChartCtrl/ChartCandlestickSerie.cpp new file mode 100644 index 0000000..2a90c4a --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartCandlestickSerie.cpp @@ -0,0 +1,243 @@ +/* + * + * ChartCandlestickSerie.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#include "stdafx.h" +#include "ChartCandlestickSerie.h" +#include "ChartCtrl.h" + +CChartCandlestickSerie::CChartCandlestickSerie(CChartCtrl* pParent) + : CChartSerieBase(pParent), m_iCandlestickWidth(7) +{ + m_bShadow = true; +} + +CChartCandlestickSerie::~CChartCandlestickSerie() +{ +} + +void CChartCandlestickSerie::AddPoint(double XVal, + double Low, + double High, + double Open, + double Close) +{ + SChartCandlestickPoint NewPoint(XVal, Low, High, Open, Close); + CChartSerieBase::AddPoint(NewPoint); +} + +void CChartCandlestickSerie::SetWidth(int Width) +{ + m_iCandlestickWidth = Width; + m_pParentCtrl->RefreshCtrl(); +} + +bool CChartCandlestickSerie::IsPointOnSerie(const CPoint& screenPoint, + unsigned& uIndex) const +{ + uIndex = INVALID_POINT; + if (!m_bIsVisible) + return false; + + unsigned uFirst=0, uLast=0; + if (!GetVisiblePoints(uFirst,uLast)) + return false; + if (uFirst>0) + uFirst--; + if (uLastValueToScreen(Point.XVal); + int ScreenLow = m_pVerticalAxis->ValueToScreen(Point.Low); + int ScreenHigh = m_pVerticalAxis->ValueToScreen(Point.High); + + int halfWidth = m_iCandlestickWidth/2; + CRect Rectangle; + if (ScreenLow > ScreenHigh) + Rectangle.SetRect(ScreenXVal-halfWidth, ScreenHigh, + ScreenXVal+halfWidth+1, ScreenLow+1); + else + Rectangle.SetRect(ScreenXVal-halfWidth, ScreenLow, + ScreenXVal+halfWidth+1, ScreenHigh+1); + if (Rectangle.PtInRect(screenPoint)) + { + bResult = true; + uIndex = i; + break; + } + } + return bResult; +} + +void CChartCandlestickSerie::DrawLegend(CDC* pDC, const CRect& rectBitmap) const +{ + if (m_strSerieName == _T("")) + return; + if (!pDC->GetSafeHdc()) + return; + + NewPen.CreatePen(PS_SOLID,1,m_SerieColor); + BrushFill.CreateSolidBrush(m_SerieColor); + CBrush* pOldBrush = pDC->SelectObject(&BrushFill); + CPen* pOldPen = pDC->SelectObject(&NewPen); + int OldBkMode = pDC->SetBkMode(TRANSPARENT); + + int margin = (rectBitmap.Width() - m_iCandlestickWidth)/2; + CRect CandleRect(rectBitmap.left+margin, rectBitmap.top+4, + rectBitmap.right-margin+1, rectBitmap.bottom-3); + pDC->Rectangle(CandleRect); + int MiddleX = rectBitmap.left + rectBitmap.Width()/2; + pDC->MoveTo(MiddleX, CandleRect.top); + pDC->LineTo(MiddleX, rectBitmap.top); + pDC->MoveTo(MiddleX, CandleRect.bottom); + pDC->LineTo(MiddleX, rectBitmap.bottom); + + pDC->SetBkMode(OldBkMode); + pDC->SelectClipRgn(NULL); + pDC->SelectObject(pOldPen); + pDC->SelectObject(pOldBrush); + BrushFill.DeleteObject(); + NewPen.DeleteObject(); +} + +void CChartCandlestickSerie::Draw(CDC* pDC) +{ + if (!m_bIsVisible) + return; + + unsigned uFirst=0, uLast=0; + if (!GetVisiblePoints(uFirst,uLast)) + return; + + if (pDC->GetSafeHdc()) + { + ShadowBrush.CreateSolidBrush(m_ShadowColor); + NewPen.CreatePen(PS_SOLID,1,m_SerieColor); + ShadowPen.CreatePen(PS_SOLID,1,m_ShadowColor); + BrushFill.CreateSolidBrush(m_SerieColor); + BrushEmpty.CreateSolidBrush(RGB(255,255,255)); + + int OldBkMode = pDC->SetBkMode(TRANSPARENT); + //To have lines limited in the drawing rectangle : + pDC->IntersectClipRect(m_PlottingRect); + + for (m_uLastDrawnPoint;m_uLastDrawnPointSetBkMode(OldBkMode); + pDC->SelectClipRgn(NULL); + BrushFill.DeleteObject(); + BrushEmpty.DeleteObject(); + NewPen.DeleteObject(); + ShadowBrush.DeleteObject(); + ShadowPen.DeleteObject(); + } +} + +void CChartCandlestickSerie::DrawAll(CDC *pDC) +{ + if (!m_bIsVisible) + return; + + unsigned uFirst=0, uLast=0; + if (!GetVisiblePoints(uFirst,uLast)) + return; + + if (pDC->GetSafeHdc()) + { + ShadowBrush.CreateSolidBrush(m_ShadowColor); + NewPen.CreatePen(PS_SOLID,1,m_SerieColor); + ShadowPen.CreatePen(PS_SOLID,1,m_ShadowColor); + BrushFill.CreateSolidBrush(m_SerieColor); + BrushEmpty.CreateSolidBrush(RGB(255,255,255)); + + pDC->SetBkMode(TRANSPARENT); + //To have lines limited in the drawing rectangle : + pDC->IntersectClipRect(m_PlottingRect); + + for (m_uLastDrawnPoint=uFirst;m_uLastDrawnPoint<=uLast;m_uLastDrawnPoint++) + { + SChartCandlestickPoint Point = GetPoint(m_uLastDrawnPoint); + DrawCandleStick(pDC, Point); + } + + pDC->SelectClipRgn(NULL); + BrushFill.DeleteObject(); + BrushEmpty.DeleteObject(); + NewPen.DeleteObject(); + ShadowBrush.DeleteObject(); + ShadowPen.DeleteObject(); + } +} + +void CChartCandlestickSerie::DrawCandleStick(CDC* pDC, SChartCandlestickPoint Point) +{ + int ScreenXVal = m_pHorizontalAxis->ValueToScreen(Point.XVal); + int ScreenOpen = m_pVerticalAxis->ValueToScreen(Point.Open); + int ScreenClose = m_pVerticalAxis->ValueToScreen(Point.Close); + int ScreenLow = m_pVerticalAxis->ValueToScreen(Point.Low); + int ScreenHigh = m_pVerticalAxis->ValueToScreen(Point.High); + + int halfWidth = m_iCandlestickWidth/2; + CPoint TopLeft, BottomRight; + CRect Body; + CRect ShadowBody; + if (ScreenOpen > ScreenClose) + Body.SetRect(ScreenXVal-halfWidth, ScreenClose, + ScreenXVal+halfWidth+1, ScreenOpen+1); + else + Body.SetRect(ScreenXVal-halfWidth, ScreenOpen, + ScreenXVal+halfWidth+1, ScreenClose+1); + + ShadowBody = Body; + ShadowBody.OffsetRect(m_iShadowDepth, m_iShadowDepth); + + CBrush* pOldBrush = pDC->SelectObject(&ShadowBrush); + CPen* pOldPen = pDC->SelectObject(&ShadowPen); + + if (m_bShadow) + pDC->Rectangle(ShadowBody); + if (Point.Open > Point.Close) + pDC->SelectObject(&BrushFill); + else + pDC->SelectObject(&BrushEmpty); + + if (m_bShadow) + { + pDC->MoveTo(ScreenXVal+m_iShadowDepth, ScreenOpen+m_iShadowDepth); + pDC->LineTo(ScreenXVal+m_iShadowDepth, ScreenHigh+m_iShadowDepth); + pDC->MoveTo(ScreenXVal+m_iShadowDepth, ScreenClose+m_iShadowDepth); + pDC->LineTo(ScreenXVal+m_iShadowDepth, ScreenLow+m_iShadowDepth); + } + pDC->SelectObject(&NewPen); + pDC->MoveTo(ScreenXVal, ScreenOpen); pDC->LineTo(ScreenXVal, ScreenHigh); + pDC->MoveTo(ScreenXVal, ScreenClose); pDC->LineTo(ScreenXVal, ScreenLow); + + pDC->Rectangle(Body); + pDC->SelectObject(pOldBrush); + pDC->SelectObject(pOldPen); +} \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartCandlestickSerie.h b/ChartDemo/ChartCtrl/ChartCandlestickSerie.h new file mode 100644 index 0000000..87d7ed8 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartCandlestickSerie.h @@ -0,0 +1,142 @@ +/* + * + * ChartCandlestickSerie.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#pragma once +#include "ChartSerieBase.h" + +//! Point structure used as template parameter for candlestick series +struct SChartCandlestickPoint +{ + SChartCandlestickPoint() { } + SChartCandlestickPoint(double XValue, double LowVal, + double HighVal, double OpenVal, double CloseVal): + XVal(XValue), Low(LowVal), High(HighVal), + Open(OpenVal), Close(CloseVal) { } + + //! The X value of the point (usually, a time) + double XVal; + //! The low market price + double Low; + //! The high market price + double High; + //! The open market price + double Open; + //! The close market price + double Close; + + //! Returns the X value of the point + double GetX() const { return XVal; } + //! Returns the Y value of the point, which is the average between low and high + double GetY() const { return (Low+High)/2; } + //! Returns the minimum X value of the point + double GetXMin() const { return XVal; } + //! Returns the maximum X value of the point + double GetXMax() const { return XVal; } + //! Returns the minimum Y value of the point (the low value) + double GetYMin() const { return Low; } + //! Returns the maximum Y value of the point (the high value) + double GetYMax() const { return High; } +}; + +//! Specialization of a CChartSerieBase to display a candlestick series. +/** + Each point in the series has an X value (the time), a high value + (the highest market price), a low value (the lowest market price), + an open value (the market price at the opening) and a close value + (the market price at the closing). +**/ +class CChartCandlestickSerie : public CChartSerieBase +{ +public: + //! Constructor + CChartCandlestickSerie(CChartCtrl* pParent); + //! Destructor + ~CChartCandlestickSerie(); + + //! Tests if a certain screen point is on the series. + /** + @param screenPoint + The screen point to test + @param uIndex + If the point is close to a specific point of the series, its index is stored here. + @return true if the point is on the series + **/ + bool IsPointOnSerie(const CPoint& screenPoint, unsigned& uIndex) const; + + //! Adds a new point in the series + /** + @param XVal + The X value of the point (the time) + @param Low + The lowest market price + @param High + The highest market price + @param Open + The market price at the opening + @param Close + The market price at the closing + **/ + void AddPoint(double XVal, double Low, double High, + double Open, double Close); + //! Sets the width (in pixels) of all candlestick points in the series + void SetWidth(int Width); + //! Returns the width (in pixels) of a point in the series + int GetWidth() { return m_iCandlestickWidth; } + +protected: + //! Draws the legend icon for the series. + /** + @param pDC + The device context used to draw + @param rectBitmap + The rectangle in which to draw the legend icon + **/ + void DrawLegend(CDC* pDC, const CRect& rectBitmap) const; + + //! Draws the most recent points of the series. + /** + This function should only draw the points that were not previously + drawn. + @param pDC + The device context used to draw + **/ + void Draw(CDC* pDC); + //! Redraws the full series. + /** + @param pDC + The device context used to draw + **/ + void DrawAll(CDC *pDC); + +private: + //! Draws a candle stick point + void DrawCandleStick(CDC *pDC, SChartCandlestickPoint Point); + + //! The candlestick width + int m_iCandlestickWidth; + + // Caches the pen and brushes to avoid creating them for each point + mutable CBrush ShadowBrush; + mutable CPen NewPen; + mutable CPen ShadowPen; + mutable CBrush BrushFill; + mutable CBrush BrushEmpty; +}; \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartCrossHairCursor.cpp b/ChartDemo/ChartCtrl/ChartCrossHairCursor.cpp new file mode 100644 index 0000000..a0bb398 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartCrossHairCursor.cpp @@ -0,0 +1,62 @@ +/* + * + * ChartCrossHairCursor.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#include "stdafx.h" +#include "ChartCrossHairCursor.h" +#include "ChartCtrl.h" + +CChartCrossHairCursor::CChartCrossHairCursor(CChartCtrl* pParent, + CChartAxis* pHorizAxis, + CChartAxis* pVertAxis) + : CChartCursor(pParent), m_pHorizontalAxis(pHorizAxis), m_pVerticalAxis(pVertAxis), + m_lXPos(0), m_lYPos(0) +{ +} + +CChartCrossHairCursor::~CChartCrossHairCursor() +{ +} + +void CChartCrossHairCursor::Draw(CDC* pDC) +{ + CPen NewPen(PS_SOLID,1,m_colCursor); + CPen* pOldPen = pDC->SelectObject(&NewPen); + + CRect plottingRect = m_pParentCtrl->GetPlottingRect(); + + pDC->MoveTo(m_lXPos, plottingRect.top); + pDC->LineTo(m_lXPos, plottingRect.bottom); + pDC->MoveTo(plottingRect.left, m_lYPos); + pDC->LineTo(plottingRect.right, m_lYPos); + + pDC->SelectObject(pOldPen); + NewPen.DeleteObject(); +} + +void CChartCrossHairCursor::OnMouseMove(CPoint mousePoint) +{ + m_lXPos = mousePoint.x; + m_lYPos = mousePoint.y; + + double XVal = m_pHorizontalAxis->ScreenToValue(m_lXPos); + double YVal = m_pVerticalAxis->ScreenToValue(m_lYPos); + CursorMoved(XVal, YVal); +} diff --git a/ChartDemo/ChartCtrl/ChartCrossHairCursor.h b/ChartDemo/ChartCtrl/ChartCrossHairCursor.h new file mode 100644 index 0000000..66b8ba2 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartCrossHairCursor.h @@ -0,0 +1,72 @@ +/* + * + * ChartCrossHairCursor.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#ifndef _CHARTCROSSHAIRCURSOR_H_ +#define _CHARTCROSSHAIRCURSOR_H_ + +#include "ChartCursor.h" + +class CChartAxis; + +//! Specialization of a CChartCursor class for a cross-hair cursor. +/** + A cross-hair cursor is a simple cross displayed in the plotting area. + The cursor moves along with the mouse (but stay within the bounds of + the plot area).
+ To create a cross-hair cursor, call the CreateCrossHairCursor from the + CChartCtrl class. +**/ +class CChartCrossHairCursor : public CChartCursor +{ + friend CChartCtrl; + +protected: + //! Called when the mouse is moved over the plot area. + void OnMouseMove(CPoint mousePoint); + //! Draws the cursor. + void Draw(CDC* pDC); + +private: + //! Constructor + /** + @param pParent + The parent charting control + @param pHorizAxis + The associated horizontal axis + @param pVertAxis + The associated vertical axis + **/ + CChartCrossHairCursor(CChartCtrl* pParent, CChartAxis* pHorizAxis, CChartAxis* pVertAxis); + //! Destructor + ~CChartCrossHairCursor(); + + //! The associated horizontal axis + CChartAxis* m_pHorizontalAxis; + //! The associated vertical axis + CChartAxis* m_pVerticalAxis; + + //! The current X screen position + long m_lXPos; + //! The current Y screen position + long m_lYPos; +}; + +#endif // _CHARTCROSSHAIRCURSOR_H_ \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartCtrl.cpp b/ChartDemo/ChartCtrl/ChartCtrl.cpp new file mode 100644 index 0000000..9cd2e03 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartCtrl.cpp @@ -0,0 +1,1143 @@ +/* + * + * ChartCtrl.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + * History: + * - 18/05/2006: Added support for panning + * - 28/05/2006: Bug corrected in RemoveAllSeries + * - 28/05/2006: Added support for resizing + * - 12/06/2006: Added support for manual zoom + * - 10/08/2006: Added SetZoomMinMax and UndoZoom + * - 24/03/2007: GDI leak corrected + * - 24/03/2007: Invisible series are not taken in account for auto axis + * and legend (thanks to jerminator-jp). + * - 24/03/2007: possibility to specify a margin for the axis. Needs to be improved + * - 05/04/2007: ability to change the text color of the axis. + * - 05/04/2007: ability to change the color of the border of the drawing area. + * - 05/04/2007: Surface series added. + * - 26/08/2007: The clipping area of the series is a bit larger (they will be + * drawn over the bottom and right axes). + * - 12/01/2007: Ability to change the color of the zoom rectangle. + * - 08/02/2008: Added convenience functions to convert from date to value and + * opposite. + * - 21/02/2008: The zoom doesn't do anything if the user only clicks on the control + * (thanks to Eugene Pustovoyt). + * - 29/02/2008: The auto axis are now refreshed when a series is removed (thanks to + * Bruno Lavier). + * - 08/03/2008: EnableRefresh function added (thanks to Bruno Lavier). + * - 21/03/2008: Added support for scrolling. + * - 25/03/2008: UndoZoom function added. + * - 25/03/2008: A series can now be removed using its pointer. + * - 12/08/2008: Performance patch (thanks to Nick Holgate). + * - 18/08/2008: Added support for printing. + * - 31/10/2008: Fixed a bug for unicode. + * + */ + +#include "stdafx.h" +#include "ChartCtrl.h" + +#include "ChartSerie.h" +#include "ChartGradient.h" +#include "ChartStandardAxis.h" +#include "ChartDateTimeAxis.h" +#include "ChartLogarithmicAxis.h" +#include "ChartCrossHairCursor.h" +#include "ChartDragLineCursor.h" + +#include "ChartPointsSerie.h" +#include "ChartLineSerie.h" +#include "ChartSurfaceSerie.h" +#include "ChartBarSerie.h" +#include "ChartCandlestickSerie.h" +#include "ChartGanttSerie.h" + +#if _MFC_VER > 0x0600 +#include "atlImage.h" +#endif + +using namespace std; + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +#define CHARTCTRL_CLASSNAME _T("ChartCtrl") // Window class name + + +COLORREF pSeriesColorTable[] = { RGB(255,0,0), RGB(0,150,0), RGB(0,0,255), RGB(255,255,0), RGB(0,255,255), + RGB(255,128,0), RGB(128,0,128), RGB(128,128,0), RGB(255,0,255), RGB(64,128,128)}; + +///////////////////////////////////////////////////////////////////////////// +// CChartCtrl + +CChartCtrl::CChartCtrl() +{ + RegisterWindowClass(); + + m_iEnableRefresh = 1; + m_bPendingRefresh = false; + m_BorderColor = RGB(0,0,0); + m_BackColor = GetSysColor(COLOR_BTNFACE); + EdgeType = EDGE_RAISED; + m_BackGradientType = gtVertical; + m_bBackGradient = false; + m_BackGradientCol1 = m_BackGradientCol2 = m_BackColor; + + for (int i=0;i<4;i++) + m_pAxes[i] = NULL; + + m_pLegend = new CChartLegend(this); + m_pTitles = new CChartTitle(this); + + m_bMemDCCreated = false; + m_bPanEnabled = true; + m_bRMouseDown = false; + + m_bZoomEnabled = true; + m_bLMouseDown = false; + m_ZoomRectColor = RGB(255,255,255); + + m_bToolBarCreated = false; + m_pMouseListener = NULL; + m_bMouseVisible = true; +} + +CChartCtrl::~CChartCtrl() +{ + TSeriesMap::iterator seriesIter = m_mapSeries.begin(); + for (seriesIter; seriesIter!=m_mapSeries.end(); seriesIter++) + { + delete (seriesIter->second); + } + TCursorMap::iterator cursorIter = m_mapCursors.begin(); + for (cursorIter; cursorIter!=m_mapCursors.end(); cursorIter++) + { + delete (cursorIter->second); + } + + for (int i=0; i<4 ;i++) + { + if (m_pAxes[i]) + delete m_pAxes[i]; + } + + if (m_pLegend) + { + delete m_pLegend; + m_pLegend = NULL; + } + if (m_pTitles) + { + delete m_pTitles; + m_pTitles = NULL; + } +} + + +BEGIN_MESSAGE_MAP(CChartCtrl, CWnd) + //{{AFX_MSG_MAP(CChartCtrl) + ON_WM_PAINT() + ON_WM_ERASEBKGND() + ON_WM_MOUSEMOVE() + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONUP() + ON_WM_LBUTTONDBLCLK() + ON_WM_RBUTTONDOWN() + ON_WM_RBUTTONUP() + ON_WM_RBUTTONDBLCLK() + ON_WM_SIZE() + ON_WM_HSCROLL() + ON_WM_VSCROLL() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// CChartCtrl message handlers + +void CChartCtrl::OnPaint() +{ + CPaintDC dc(this); // device context for painting + + if (!m_bMemDCCreated) + { + RefreshCtrl(); + m_bMemDCCreated = true; + } + + // Get Size of Display area + CRect rect; + GetClientRect(&rect); + dc.BitBlt(0, 0, rect.Width(), rect.Height(), + &m_BackgroundDC, 0, 0, SRCCOPY) ; + + // Draw the zoom rectangle + if (m_bZoomEnabled && m_bLMouseDown) + { + CPen NewPen(PS_SOLID,1,m_ZoomRectColor); + CPen* pOldPen = dc.SelectObject(&NewPen); + + dc.MoveTo(m_rectZoomArea.TopLeft()); + dc.LineTo(m_rectZoomArea.right,m_rectZoomArea.top); + dc.LineTo(m_rectZoomArea.BottomRight()); + dc.LineTo(m_rectZoomArea.left,m_rectZoomArea.bottom); + dc.LineTo(m_rectZoomArea.TopLeft()); + + dc.SelectObject(pOldPen); + DeleteObject(NewPen); + } + + // Draw the cursors. + TCursorMap::iterator iter = m_mapCursors.begin(); + for (iter; iter!=m_mapCursors.end(); iter++) + iter->second->Draw(&dc); +} + +BOOL CChartCtrl::OnEraseBkgnd(CDC* ) +{ + // To avoid flickering +// return CWnd::OnEraseBkgnd(pDC); + return FALSE; +} + +CChartCrossHairCursor* CChartCtrl::CreateCrossHairCursor(bool bSecondaryHorizAxis, + bool bSecondaryVertAxis) +{ + CChartAxis* pHorizAxis = NULL; + CChartAxis* pVertAxis = NULL; + if (bSecondaryHorizAxis) + pHorizAxis = m_pAxes[TopAxis]; + else + pHorizAxis = m_pAxes[BottomAxis]; + if (bSecondaryVertAxis) + pVertAxis = m_pAxes[RightAxis]; + else + pVertAxis = m_pAxes[LeftAxis]; + + ASSERT(pHorizAxis != NULL); + ASSERT(pVertAxis != NULL); + + CChartCrossHairCursor* pNewCursor = new CChartCrossHairCursor(this, pHorizAxis, pVertAxis); + m_mapCursors[pNewCursor->GetCursorId()] = pNewCursor; + return pNewCursor; +} + +CChartDragLineCursor* CChartCtrl::CreateDragLineCursor(EAxisPos relatedAxis) +{ + ASSERT(m_pAxes[relatedAxis] != NULL); + + CChartDragLineCursor* pNewCursor = new CChartDragLineCursor(this, m_pAxes[relatedAxis]); + m_mapCursors[pNewCursor->GetCursorId()] = pNewCursor; + return pNewCursor; +} + +void CChartCtrl::AttachCustomCursor(CChartCursor* pCursor) +{ + m_mapCursors[pCursor->GetCursorId()] = pCursor; +} + +void CChartCtrl::RemoveCursor(unsigned cursorId) +{ + TCursorMap::iterator iter = m_mapCursors.find(cursorId); + if (iter != m_mapCursors.end()) + { + delete iter->second; + m_mapCursors.erase(iter); + } +} + +void CChartCtrl::ShowMouseCursor(bool bShow) +{ + m_bMouseVisible = bShow; + if (!bShow) + SetCursor(NULL); +} + +CChartStandardAxis* CChartCtrl::CreateStandardAxis(EAxisPos axisPos) +{ + CChartStandardAxis* pAxis = new CChartStandardAxis(); + AttachCustomAxis(pAxis, axisPos); + return pAxis; +} + +CChartLogarithmicAxis* CChartCtrl::CreateLogarithmicAxis(EAxisPos axisPos) +{ + CChartLogarithmicAxis* pAxis = new CChartLogarithmicAxis(); + AttachCustomAxis(pAxis, axisPos); + return pAxis; +} + +CChartDateTimeAxis* CChartCtrl::CreateDateTimeAxis(EAxisPos axisPos) +{ + CChartDateTimeAxis* pAxis = new CChartDateTimeAxis(); + AttachCustomAxis(pAxis, axisPos); + return pAxis; +} + +void CChartCtrl::AttachCustomAxis(CChartAxis* pAxis, EAxisPos axisPos) +{ + // The axis should not be already attached to another control + ASSERT(pAxis->m_pParentCtrl == NULL); + pAxis->SetParent(this); + + if ( (axisPos==RightAxis) || (axisPos==TopAxis) ) + pAxis->SetSecondary(true); + if ( (axisPos==BottomAxis) || (axisPos==TopAxis) ) + pAxis->SetHorizontal(true); + else + pAxis->SetHorizontal(false); + pAxis->CreateScrollBar(); + + // Beofre storing the new axis, we should delete the previous one if any + if (m_pAxes[axisPos]) + delete m_pAxes[axisPos]; + m_pAxes[axisPos] = pAxis; +} + +bool CChartCtrl::RegisterWindowClass() +{ + WNDCLASS wndcls; + HINSTANCE hInst = AfxGetInstanceHandle(); + + if (!(::GetClassInfo(hInst, CHARTCTRL_CLASSNAME, &wndcls))) + { + memset(&wndcls, 0, sizeof(WNDCLASS)); + + wndcls.hInstance = hInst; + wndcls.lpfnWndProc = ::DefWindowProc; + wndcls.hCursor = NULL; //LoadCursor(NULL, IDC_ARROW); + wndcls.hIcon = 0; + wndcls.lpszMenuName = NULL; + wndcls.hbrBackground = (HBRUSH) ::GetStockObject(WHITE_BRUSH); + wndcls.style = CS_DBLCLKS; + wndcls.cbClsExtra = 0; + wndcls.cbWndExtra = 0; + wndcls.lpszClassName = CHARTCTRL_CLASSNAME; + + if (!RegisterClass(&wndcls)) + { + // AfxThrowResourceException(); + return false; + } + } + + return true; + +} + +int CChartCtrl::Create(CWnd *pParentWnd, const RECT &rect, UINT nID, DWORD dwStyle) +{ + dwStyle |= WS_CLIPCHILDREN; + int Result = CWnd::Create(CHARTCTRL_CLASSNAME, _T(""), dwStyle, rect, pParentWnd, nID); + + if (Result) + RefreshCtrl(); + + return Result; +} + +void CChartCtrl::SetBackGradient(COLORREF Col1, COLORREF Col2, EGradientType GradientType) +{ + m_bBackGradient = true; + m_BackGradientCol1 = Col1; + m_BackGradientCol2 = Col2; + m_BackGradientType = GradientType; + RefreshCtrl(); +} + +void CChartCtrl::EnableRefresh(bool bEnable) +{ + if (bEnable) + m_iEnableRefresh++; + else + m_iEnableRefresh--; + if (m_iEnableRefresh > 0 && m_bPendingRefresh) + { + m_bPendingRefresh = false; + RefreshCtrl(); + } +} + +void CChartCtrl::UndoPanZoom() +{ + EnableRefresh(false); + if (m_pAxes[BottomAxis]) + m_pAxes[BottomAxis]->UndoZoom(); + if (m_pAxes[LeftAxis]) + m_pAxes[LeftAxis]->UndoZoom(); + if (m_pAxes[TopAxis]) + m_pAxes[TopAxis]->UndoZoom(); + if (m_pAxes[RightAxis]) + m_pAxes[RightAxis]->UndoZoom(); + EnableRefresh(true); +} + +void CChartCtrl::RefreshCtrl() +{ + // Window is not created yet, so skip the refresh. + if (!GetSafeHwnd()) + return; + if (m_iEnableRefresh < 1) + { + m_bPendingRefresh = true; + return; + } + + // Retrieve the client rect and initialize the + // plotting rect + CClientDC dc(this) ; + CRect ClientRect; + GetClientRect(&ClientRect); + m_PlottingRect = ClientRect; + + // If the backgroundDC was not created yet, create it (it + // is used to avoid flickering). + if (!m_BackgroundDC.GetSafeHdc() ) + { + CBitmap memBitmap; + m_BackgroundDC.CreateCompatibleDC(&dc) ; + memBitmap.CreateCompatibleBitmap(&dc, ClientRect.Width(),ClientRect.Height()) ; + m_BackgroundDC.SelectObject(&memBitmap) ; + } + + // Draw the chart background, which is not part of + // the DrawChart function (to avoid a background when + // printing). + DrawBackground(&m_BackgroundDC, ClientRect); + ClientRect.DeflateRect(3,3); + DrawChart(&m_BackgroundDC,ClientRect); + for (int i=0; i<4 ;i++) + { + if (m_pAxes[i]) + m_pAxes[i]->UpdateScrollBarPos(); + } + Invalidate(); +} + +void CChartCtrl::DrawChart(CDC* pDC, CRect ChartRect) +{ + m_PlottingRect = ChartRect; + CSize TitleSize = m_pTitles->GetSize(pDC); + CRect rcTitle; + rcTitle = ChartRect; + rcTitle.bottom = TitleSize.cy; + + ChartRect.top += TitleSize.cy; + m_pTitles->SetTitleRect(rcTitle); + m_pTitles->Draw(pDC); + + m_pLegend->ClipArea(ChartRect,pDC); + + //Clip all the margins (axis) of the client rect + int n=0; + for (n=0;n<4;n++) + { + if (m_pAxes[n]) + { + m_pAxes[n]->SetAxisSize(ChartRect,m_PlottingRect); + m_pAxes[n]->Recalculate(); + m_pAxes[n]->ClipMargin(ChartRect,m_PlottingRect,pDC); + } + } + for (n=0;n<4;n++) + { + if (m_pAxes[n]) + { + m_pAxes[n]->SetAxisSize(ChartRect,m_PlottingRect); + m_pAxes[n]->Recalculate(); + m_pAxes[n]->Draw(pDC); + } + } + + CPen SolidPen(PS_SOLID,0,m_BorderColor); + CPen* pOldPen = pDC->SelectObject(&SolidPen); + + pDC->MoveTo(m_PlottingRect.left,m_PlottingRect.top); + pDC->LineTo(m_PlottingRect.right,m_PlottingRect.top); + pDC->LineTo(m_PlottingRect.right,m_PlottingRect.bottom); + pDC->LineTo(m_PlottingRect.left,m_PlottingRect.bottom); + pDC->LineTo(m_PlottingRect.left,m_PlottingRect.top); + + pDC->SelectObject(pOldPen); + DeleteObject(SolidPen); + + TSeriesMap::iterator iter = m_mapSeries.begin(); + for (iter; iter!=m_mapSeries.end(); iter++) + { + CRect drawingRect = m_PlottingRect; + drawingRect.bottom += 1; + drawingRect.right += 1; + iter->second->SetPlottingRect(drawingRect); + iter->second->DrawAll(pDC); + } + + pDC->IntersectClipRect(m_PlottingRect); + // Draw the labels when all series have been drawn + for (iter=m_mapSeries.begin(); iter!=m_mapSeries.end(); iter++) + { + iter->second->DrawLabels(pDC); + } + pDC->SelectClipRgn(NULL); + + // Draw the legend at the end (when floating it should come over the plotting area). + m_pLegend->Draw(pDC); +} + +void CChartCtrl::DrawBackground(CDC* pDC, CRect ChartRect) +{ + CBrush BrushBack; + BrushBack.CreateSolidBrush(m_BackColor) ; + if (!m_bBackGradient) + { + pDC->SetBkColor(m_BackColor); + pDC->FillRect(ChartRect,&BrushBack); + } + else + { + CChartGradient::DrawGradient(pDC,ChartRect,m_BackGradientCol1, + m_BackGradientCol2,m_BackGradientType); + } + + // Draw the edge. + pDC->DrawEdge(ChartRect,EdgeType,BF_RECT); +} + +void CChartCtrl::RefreshScreenAutoAxes() +{ + for (int n=0;n<4;n++) + { + if (m_pAxes[n]) + m_pAxes[n]->RefreshScreenAutoAxis(); + } +} + +CChartPointsSerie* CChartCtrl::CreatePointsSerie(bool bSecondaryHorizAxis, + bool bSecondaryVertAxis) +{ + CChartPointsSerie* pNewSerie = new CChartPointsSerie(this); + AttachCustomSerie(pNewSerie, bSecondaryHorizAxis, bSecondaryVertAxis); + return pNewSerie; +} + +CChartLineSerie* CChartCtrl::CreateLineSerie(bool bSecondaryHorizAxis, + bool bSecondaryVertAxis) +{ + CChartLineSerie* pNewSerie = new CChartLineSerie(this); + AttachCustomSerie(pNewSerie, bSecondaryHorizAxis, bSecondaryVertAxis); + return pNewSerie; +} + +CChartSurfaceSerie* CChartCtrl::CreateSurfaceSerie(bool bSecondaryHorizAxis, + bool bSecondaryVertAxis) +{ + CChartSurfaceSerie* pNewSerie = new CChartSurfaceSerie(this); + AttachCustomSerie(pNewSerie, bSecondaryHorizAxis, bSecondaryVertAxis); + return pNewSerie; +} + +CChartBarSerie* CChartCtrl::CreateBarSerie(bool bSecondaryHorizAxis, + bool bSecondaryVertAxis) +{ + CChartBarSerie* pNewSerie = new CChartBarSerie(this); + AttachCustomSerie(pNewSerie, bSecondaryHorizAxis, bSecondaryVertAxis); + return pNewSerie; +} + +CChartCandlestickSerie* CChartCtrl::CreateCandlestickSerie(bool bSecondaryHorizAxis, + bool bSecondaryVertAxis) +{ + CChartCandlestickSerie* pNewSerie = new CChartCandlestickSerie(this); + AttachCustomSerie(pNewSerie, bSecondaryHorizAxis, bSecondaryVertAxis); + return pNewSerie; +} + +CChartGanttSerie* CChartCtrl::CreateGanttSerie(bool bSecondaryHorizAxis, + bool bSecondaryVertAxis) +{ + CChartGanttSerie* pNewSerie = new CChartGanttSerie(this); + AttachCustomSerie(pNewSerie, bSecondaryHorizAxis, bSecondaryVertAxis); + return pNewSerie; +} + +void CChartCtrl::AttachCustomSerie(CChartSerie* pNewSeries, + bool bSecondaryHorizAxis, + bool bSecondaryVertAxis) +{ + size_t ColIndex = m_mapSeries.size()%10; + + CChartAxis* pHorizAxis = NULL; + CChartAxis* pVertAxis = NULL; + if (bSecondaryHorizAxis) + pHorizAxis = m_pAxes[TopAxis]; + else + pHorizAxis = m_pAxes[BottomAxis]; + if (bSecondaryVertAxis) + pVertAxis = m_pAxes[RightAxis]; + else + pVertAxis = m_pAxes[LeftAxis]; + + ASSERT(pHorizAxis != NULL); + ASSERT(pVertAxis != NULL); + + if (pNewSeries) + { + pNewSeries->SetPlottingRect(m_PlottingRect); + pNewSeries->SetColor(pSeriesColorTable[ColIndex]); + pNewSeries->m_pHorizontalAxis = pHorizAxis; + pNewSeries->m_pVerticalAxis = pVertAxis; + m_mapSeries[pNewSeries->GetSerieId()] = pNewSeries; + + EnableRefresh(false); + pVertAxis->RegisterSeries(pNewSeries); + pVertAxis->RefreshAutoAxis(); + pHorizAxis->RegisterSeries(pNewSeries); + pHorizAxis->RefreshAutoAxis(); + + // The series will need to be redrawn so we need to refresh the control + RefreshCtrl(); + EnableRefresh(true); + } +} + +CChartSerie* CChartCtrl::GetSerie(size_t uSerieId) const +{ + CChartSerie* pToReturn = NULL; + TSeriesMap::const_iterator iter = m_mapSeries.find(uSerieId); + if (iter != m_mapSeries.end()) + { + pToReturn = iter->second; + } + + return pToReturn; +} + +void CChartCtrl::RemoveSerie(unsigned uSerieId) +{ + TSeriesMap::iterator iter = m_mapSeries.find(uSerieId); + if (iter != m_mapSeries.end()) + { + CChartSerie* pToDelete = iter->second; + m_mapSeries.erase(iter); + + EnableRefresh(false); + pToDelete->m_pVerticalAxis->UnregisterSeries(pToDelete); + pToDelete->m_pHorizontalAxis->UnregisterSeries(pToDelete); + pToDelete->m_pVerticalAxis->RefreshAutoAxis(); + pToDelete->m_pHorizontalAxis->RefreshAutoAxis(); + delete pToDelete; + RefreshCtrl(); + EnableRefresh(true); + } +} + +void CChartCtrl::RemoveAllSeries() +{ + TSeriesMap::iterator iter = m_mapSeries.begin(); + for (iter; iter != m_mapSeries.end(); iter++) + { + delete iter->second; + } + + m_mapSeries.clear(); + RefreshCtrl(); +} + + +CChartAxis* CChartCtrl::GetBottomAxis() const +{ + return (m_pAxes[BottomAxis]); +} + +CChartAxis* CChartCtrl::GetLeftAxis() const +{ + return (m_pAxes[LeftAxis]); +} + +CChartAxis* CChartCtrl::GetTopAxis() const +{ + return (m_pAxes[TopAxis]); +} + +CChartAxis* CChartCtrl::GetRightAxis() const +{ + return (m_pAxes[RightAxis]); +} + + +CDC* CChartCtrl::GetDC() +{ + return &m_BackgroundDC; +} + + +size_t CChartCtrl::GetSeriesCount() const +{ + return m_mapSeries.size(); +} + +///////////////////////////////////////////////////////////////////////////// +// Mouse events + +void CChartCtrl::OnMouseMove(UINT nFlags, CPoint point) +{ + if (m_bRMouseDown && m_bPanEnabled) + { + if (point != m_PanAnchor) + { + EnableRefresh(false); + if (m_pAxes[LeftAxis]) + m_pAxes[LeftAxis]->PanAxis(m_PanAnchor.y,point.y); + if (m_pAxes[RightAxis]) + m_pAxes[RightAxis]->PanAxis(m_PanAnchor.y,point.y); + if (m_pAxes[BottomAxis]) + m_pAxes[BottomAxis]->PanAxis(m_PanAnchor.x,point.x); + if (m_pAxes[TopAxis]) + m_pAxes[TopAxis]->PanAxis(m_PanAnchor.x,point.x); + RefreshCtrl(); + EnableRefresh(true); + // Force an immediate repaint of the window, so that the mouse messages + // are by passed (this allows for a smooth pan) + UpdateWindow(); + + m_PanAnchor = point; + } + } + + if (m_bLMouseDown && m_bZoomEnabled) + { + m_rectZoomArea.BottomRight() = point; + Invalidate(); + } + + for (int i=0; i<4; i++) + { + if (m_pAxes[i]) + m_pAxes[i]->m_pScrollBar->OnMouseLeave(); + } + CWnd* pWnd = ChildWindowFromPoint(point); + if (pWnd != this) + { + CChartScrollBar* pScrollBar = dynamic_cast(pWnd); + if (pScrollBar) + pScrollBar->OnMouseEnter(); + } + + if (m_PlottingRect.PtInRect(point)) + { + TCursorMap::iterator iter = m_mapCursors.begin(); + for (iter; iter!=m_mapCursors.end(); iter++) + iter->second->OnMouseMove(point); + + Invalidate(); + } + + if (!m_bMouseVisible && m_PlottingRect.PtInRect(point)) + SetCursor(NULL); + else + SetCursor(::LoadCursor(NULL,IDC_ARROW)); + + SendMouseEvent(CChartMouseListener::MouseMove, point); + CWnd::OnMouseMove(nFlags, point); +} + +void CChartCtrl::OnLButtonDown(UINT nFlags, CPoint point) +{ + SetCapture(); + if (m_bZoomEnabled) + { + m_bLMouseDown = true; + m_rectZoomArea.TopLeft() = point; + m_rectZoomArea.BottomRight() = point; + } + + if (m_PlottingRect.PtInRect(point)) + { + TCursorMap::iterator iter = m_mapCursors.begin(); + for (iter; iter!=m_mapCursors.end(); iter++) + iter->second->OnMouseButtonDown(point); + + Invalidate(); + } + + SendMouseEvent(CChartMouseListener::LButtonDown, point); + CWnd::OnLButtonDown(nFlags, point); +} + +void CChartCtrl::OnLButtonUp(UINT nFlags, CPoint point) +{ + ReleaseCapture(); + m_bLMouseDown = false; + if (m_bZoomEnabled) + { + if ( (m_rectZoomArea.left > m_rectZoomArea.right) || + (m_rectZoomArea.top > m_rectZoomArea.bottom)) + { + UndoPanZoom(); + } + else if ( (m_rectZoomArea.left!=m_rectZoomArea.right) && + (m_rectZoomArea.top!=m_rectZoomArea.bottom)) + { + double MinVal = 0; + double MaxVal = 0; + + if (m_pAxes[BottomAxis]) + { + if (m_pAxes[BottomAxis]->IsInverted()) + { + MaxVal = m_pAxes[BottomAxis]->ScreenToValue(m_rectZoomArea.left); + MinVal = m_pAxes[BottomAxis]->ScreenToValue(m_rectZoomArea.right); + } + else + { + MinVal = m_pAxes[BottomAxis]->ScreenToValue(m_rectZoomArea.left); + MaxVal = m_pAxes[BottomAxis]->ScreenToValue(m_rectZoomArea.right); + } + m_pAxes[BottomAxis]->SetZoomMinMax(MinVal,MaxVal); + } + + if (m_pAxes[LeftAxis]) + { + if (m_pAxes[LeftAxis]->IsInverted()) + { + MaxVal = m_pAxes[LeftAxis]->ScreenToValue(m_rectZoomArea.bottom); + MinVal = m_pAxes[LeftAxis]->ScreenToValue(m_rectZoomArea.top); + } + else + { + MinVal = m_pAxes[LeftAxis]->ScreenToValue(m_rectZoomArea.bottom); + MaxVal = m_pAxes[LeftAxis]->ScreenToValue(m_rectZoomArea.top); + } + m_pAxes[LeftAxis]->SetZoomMinMax(MinVal,MaxVal); + } + + if (m_pAxes[TopAxis]) + { + if (m_pAxes[TopAxis]->IsInverted()) + { + MaxVal = m_pAxes[TopAxis]->ScreenToValue(m_rectZoomArea.left); + MinVal = m_pAxes[TopAxis]->ScreenToValue(m_rectZoomArea.right); + } + else + { + MinVal = m_pAxes[TopAxis]->ScreenToValue(m_rectZoomArea.left); + MaxVal = m_pAxes[TopAxis]->ScreenToValue(m_rectZoomArea.right); + } + m_pAxes[TopAxis]->SetZoomMinMax(MinVal,MaxVal); + } + + if (m_pAxes[RightAxis]) + { + if (m_pAxes[RightAxis]->IsInverted()) + { + MaxVal = m_pAxes[RightAxis]->ScreenToValue(m_rectZoomArea.bottom); + MinVal = m_pAxes[RightAxis]->ScreenToValue(m_rectZoomArea.top); + } + else + { + MinVal = m_pAxes[RightAxis]->ScreenToValue(m_rectZoomArea.bottom); + MaxVal = m_pAxes[RightAxis]->ScreenToValue(m_rectZoomArea.top); + } + m_pAxes[RightAxis]->SetZoomMinMax(MinVal,MaxVal); + } + + RefreshCtrl(); + } + } + + if (m_PlottingRect.PtInRect(point)) + { + TCursorMap::iterator iter = m_mapCursors.begin(); + for (iter; iter!=m_mapCursors.end(); iter++) + iter->second->OnMouseButtonUp(point); + + Invalidate(); + } + + SendMouseEvent(CChartMouseListener::LButtonUp, point); + CWnd::OnLButtonUp(nFlags, point); +} + +void CChartCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) +{ + SendMouseEvent(CChartMouseListener::LButtonDoubleClick, point); + CWnd::OnLButtonDblClk(nFlags, point); +} + +void CChartCtrl::OnRButtonDown(UINT nFlags, CPoint point) +{ + SetCapture(); + m_bRMouseDown = true; + if (m_bPanEnabled) + m_PanAnchor = point; + + SendMouseEvent(CChartMouseListener::RButtonDown, point); + CWnd::OnRButtonDown(nFlags, point); +} + +void CChartCtrl::OnRButtonUp(UINT nFlags, CPoint point) +{ + ReleaseCapture(); + m_bRMouseDown = false; + + SendMouseEvent(CChartMouseListener::RButtonUp, point); + CWnd::OnRButtonUp(nFlags, point); +} + +void CChartCtrl::OnRButtonDblClk(UINT nFlags, CPoint point) +{ + SendMouseEvent(CChartMouseListener::RButtonDoubleClick, point); + CWnd::OnRButtonDblClk(nFlags, point); +} + +void CChartCtrl::SendMouseEvent(CChartMouseListener::MouseEvent mouseEvent, + const CPoint& screenPoint) const +{ + if (m_pMouseListener) + { + // Check where the click occured. + if (m_pTitles->IsPointInside(screenPoint)) + m_pMouseListener->OnMouseEventTitle(mouseEvent,screenPoint); + if (m_pLegend->IsPointInside(screenPoint)) + m_pMouseListener->OnMouseEventLegend(mouseEvent,screenPoint); + for (int i=0; i<4; i++) + { + if ( m_pAxes[i] && m_pAxes[i]->IsPointInside(screenPoint) ) + m_pMouseListener->OnMouseEventAxis(mouseEvent,screenPoint,m_pAxes[i]); + } + if (m_PlottingRect.PtInRect(screenPoint)) + m_pMouseListener->OnMouseEventPlotArea(mouseEvent,screenPoint); + } + + // Check all the series in reverse order (check the series on top first). + TSeriesMap::const_reverse_iterator rIter = m_mapSeries.rbegin(); + for(rIter; rIter!=m_mapSeries.rend(); rIter++) + { + if (rIter->second->OnMouseEvent(mouseEvent, screenPoint)) + break; + } +} + +void CChartCtrl::OnSize(UINT nType, int cx, int cy) +{ + CWnd::OnSize(nType, cx, cy); + + // Force recreation of background DC + if (m_BackgroundDC.GetSafeHdc() ) + m_BackgroundDC.DeleteDC(); + + RefreshCtrl(); +} + +double CChartCtrl::DateToValue(const COleDateTime& Date) +{ + return (DATE)Date; +} + +COleDateTime CChartCtrl::ValueToDate(double Value) +{ + COleDateTime RetDate((DATE)Value); + return RetDate; +} + +void CChartCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + CChartScrollBar* pChartBar = dynamic_cast(pScrollBar); + if (pChartBar) + pChartBar->OnHScroll(nSBCode, nPos); + + CWnd::OnHScroll(nSBCode, nPos, pScrollBar); + RefreshCtrl(); +} + +void CChartCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + CChartScrollBar* pChartBar = dynamic_cast(pScrollBar); + if (pChartBar) + pChartBar->OnVScroll(nSBCode, nPos); + + CWnd::OnVScroll(nSBCode, nPos, pScrollBar); + RefreshCtrl(); +} + +void CChartCtrl::Print(const TChartString& strTitle, CPrintDialog* pPrntDialog) +{ + CDC dc; + if (pPrntDialog == NULL) + { + CPrintDialog printDlg(FALSE); + if (printDlg.DoModal() != IDOK) // Get printer settings from user + return; + + dc.Attach(printDlg.GetPrinterDC()); // attach a printer DC + } + else + dc.Attach(pPrntDialog->GetPrinterDC()); // attach a printer DC + dc.m_bPrinting = TRUE; + + DOCINFO di; // Initialise print doc details + memset(&di, 0, sizeof (DOCINFO)); + di.cbSize = sizeof (DOCINFO); + di.lpszDocName = strTitle.c_str(); + + BOOL bPrintingOK = dc.StartDoc(&di); // Begin a new print job + + CPrintInfo Info; + Info.m_rectDraw.SetRect(0,0, dc.GetDeviceCaps(HORZRES), dc.GetDeviceCaps(VERTRES)); + + OnBeginPrinting(&dc, &Info); // Initialise printing + for (UINT page = Info.GetMinPage(); page <= Info.GetMaxPage() && bPrintingOK; page++) + { + dc.StartPage(); // begin new page + Info.m_nCurPage = page; + OnPrint(&dc, &Info); // Print page + bPrintingOK = (dc.EndPage() > 0); // end page + } + OnEndPrinting(&dc, &Info); // Clean up after printing + + if (bPrintingOK) + dc.EndDoc(); // end a print job + else + dc.AbortDoc(); // abort job. + + dc.Detach(); // detach the printer DC +} + +void CChartCtrl::OnBeginPrinting(CDC *pDC, CPrintInfo *pInfo) +{ + // OnBeginPrinting() is called after the user has committed to + // printing by OK'ing the Print dialog, and after the framework + // has created a CDC object for the printer or the preview view. + + // This is the right opportunity to set up the page range. + // Given the CDC object, we can determine how many rows will + // fit on a page, so we can in turn determine how many printed + // pages represent the entire document. + ASSERT(pDC && pInfo); + + // Get a DC for the current window (will be a screen DC for print previewing) + CDC *pCurrentDC = GetDC(); // will have dimensions of the client area + if (!pCurrentDC) + return; + + CSize PaperPixelsPerInch(pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY)); + CSize ScreenPixelsPerInch(pCurrentDC->GetDeviceCaps(LOGPIXELSX), pCurrentDC->GetDeviceCaps(LOGPIXELSY)); + + // Create the printer font + int nFontSize = -10; + CString strFontName = _T("Arial"); + m_PrinterFont.CreateFont(nFontSize, 0,0,0, FW_NORMAL, 0,0,0, DEFAULT_CHARSET, + OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, + DEFAULT_PITCH | FF_DONTCARE, strFontName); + CFont *pOldFont = pDC->SelectObject(&m_PrinterFont); + + // Get the page sizes (physical and logical) + m_PaperSize = CSize(pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES)); + + m_LogicalPageSize.cx = ScreenPixelsPerInch.cx * m_PaperSize.cx / PaperPixelsPerInch.cx * 3 / 4; + m_LogicalPageSize.cy = ScreenPixelsPerInch.cy * m_PaperSize.cy / PaperPixelsPerInch.cy * 3 / 4; + + + // Set up the print info + pInfo->SetMaxPage(1); + pInfo->m_nCurPage = 1; // start printing at page# 1 + + ReleaseDC(pCurrentDC); + pDC->SelectObject(pOldFont); +} + +void CChartCtrl::OnPrint(CDC *pDC, CPrintInfo *pInfo) +{ + if (!pDC || !pInfo) + return; + + CFont *pOldFont = pDC->SelectObject(&m_PrinterFont); + + // Set the page map mode to use GraphCtrl units + pDC->SetMapMode(MM_ANISOTROPIC); + pDC->SetWindowExt(m_LogicalPageSize); + pDC->SetViewportExt(m_PaperSize); + pDC->SetWindowOrg(0, 0); + + // Header + pInfo->m_rectDraw.top = 0; + pInfo->m_rectDraw.left = 0; + pInfo->m_rectDraw.right = m_LogicalPageSize.cx; + pInfo->m_rectDraw.bottom = m_LogicalPageSize.cy; + + DrawChart(pDC, &pInfo->m_rectDraw); + + // SetWindowOrg back for next page + pDC->SetWindowOrg(0,0); + + pDC->SelectObject(pOldFont); +} + +void CChartCtrl::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) +{ + m_PrinterFont.DeleteObject(); + // RefreshCtrl is needed because the print job + // modifies the chart components (axis, ...) + RefreshCtrl(); +} + +void CChartCtrl::GoToFirstSerie() +{ + m_currentSeries = m_mapSeries.begin(); +} + +CChartSerie* CChartCtrl::GetNextSerie() +{ + CChartSerie* pSeries = NULL; + if (m_currentSeries != m_mapSeries.end()) + { + pSeries = m_currentSeries->second; + m_currentSeries++; + } + + return pSeries; +} + +#if _MFC_VER > 0x0600 +void CChartCtrl::SaveAsImage(const TChartString& strFilename, + const CRect& rect, + int nBPP, + REFGUID guidFileType) +{ + CImage chartImage; + CRect chartRect = rect; + if (chartRect.IsRectEmpty()) + { + GetClientRect(&chartRect); + } + + chartImage.Create(chartRect.Width(), chartRect.Height(), nBPP); + CDC newDC; + newDC.Attach(chartImage.GetDC()); + + DrawBackground(&newDC, chartRect); + chartRect.DeflateRect(3,3); + DrawChart(&newDC, chartRect); + + newDC.Detach(); + chartImage.Save(strFilename.c_str(), guidFileType); + chartImage.ReleaseDC(); +} +#endif diff --git a/ChartDemo/ChartCtrl/ChartCtrl.h b/ChartDemo/ChartCtrl/ChartCtrl.h new file mode 100644 index 0000000..c733d57 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartCtrl.h @@ -0,0 +1,586 @@ +/* + * + * ChartCtrl.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + + +#pragma once + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#include "ChartSerie.h" +#include "ChartAxis.h" +#include "ChartGrid.h" +#include "ChartLegend.h" +#include "ChartTitle.h" +#include "ChartGradient.h" +#include "ChartCursor.h" +#include "ChartMouseListener.h" +#include "ChartStandardAxis.h" +#include "ChartLogarithmicAxis.h" +#include "ChartDateTimeAxis.h" +#include "ChartCrossHairCursor.h" +#include "ChartDragLineCursor.h" + +#include + + +class CChartStandardAxis; +class CChartLogarithmicAxis; +class CChartDateTimeAxis; +class CChartCrossHairCursor; +class CChartDragLineCursor; + +class CChartPointsSerie; +class CChartLineSerie; +class CChartSurfaceSerie; +class CChartBarSerie; +class CChartCandlestickSerie; +class CChartGanttSerie; + +///////////////////////////////////////////////////////////////////////////// +// CChartCtrl window + +//! The main chart control class. +/** + +**/ +class CChartCtrl : public CWnd +{ + +public: + //! Retrieves de device context. + /** + This function is used for internal purposes only. + **/ + CDC* GetDC(); + //! Retrieves the plotting rectangle. + CRect GetPlottingRect() const { return m_PlottingRect; } + + //! Returns a pointer to the legend object. + CChartLegend* GetLegend() const { return m_pLegend; } + //! Returns a pointer to the title object. + CChartTitle* GetTitle() const { return m_pTitles; } + + //! An enumeration of the different axis positions. + enum EAxisPos + { + LeftAxis = 0, + BottomAxis, + RightAxis, + TopAxis + }; + + //! Create and attach a standard axis to the control. + /** + @param axisPos + The position of the axis. + @return The created standard axis. + **/ + CChartStandardAxis* CreateStandardAxis(EAxisPos axisPos); + //! Create and attach a logarithmic axis to the control. + /** + @param axisPos + The position of the axis. + @return The created logarithmic axis. + **/ + CChartLogarithmicAxis* CreateLogarithmicAxis(EAxisPos axisPos); + //! Create and attach a date/time axis to the control. + /** + @param axisPos + The position of the axis. + @return The created date/time axis. + **/ + CChartDateTimeAxis* CreateDateTimeAxis(EAxisPos axisPos); + //! Attach a custom axis to the control. + /** + This function takes ownership of the axis pointer, so you + must not destroy it. If the axis is alread attached to a + chart control (even this one), the function will fail with + an assertion. This function should be used only when you want + to provide a custom axis to the control, otherwise you should + use the AttachStandardAxis, AttachLogarithmicAxis and + AttachDateTimeAxis instead. + @param pAxis + The axis to attach to the control. + @param axisPos + The position of the axis. This value can be: + - LeftAxis + - BottomAxis + - RightAxis + - TopAxis + **/ + void AttachCustomAxis(CChartAxis* pAxis, EAxisPos axisPos); + + //! Create and attach a point series to the control + /** + @param bSecondaryHorizAxis + Specifies if the horizontal axis is the secondary axis or not. + @param bSecondaryVertAxis + Specifies if the vertical axis is the secondary axis or not. + @return The created chart point series. + @remark The function will assert if the associated axes are not attached + to the control. + @see AttachCustomSerie for more info about the parameters of the function. + **/ + CChartPointsSerie* CreatePointsSerie(bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false); + //! Create and attach a line series to the control + /** + The function will assert if the associated axes are not attached + to the control. + @param bSecondaryHorizAxis + Specifies if the horizontal axis is the secondary axis or not. + @param bSecondaryVertAxis + Specifies if the vertical axis is the secondary axis or not. + @return The created chart line series. + @remark The function will assert if the associated axes are not attached + to the control. + @see AttachCustomSerie for more info about the parameters of the function. + **/ + CChartLineSerie* CreateLineSerie(bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false); + //! Create and attach a surface series to the control + /** + The function will assert if the associated axes are not attached + to the control. + @param bSecondaryHorizAxis + Specifies if the horizontal axis is the secondary axis or not. + @param bSecondaryVertAxis + Specifies if the vertical axis is the secondary axis or not. + @return The created chart surface series. + @remark The function will assert if the associated axes are not attached + to the control. + @see AttachCustomSerie for more info about the parameters of the function. + **/ + CChartSurfaceSerie* CreateSurfaceSerie(bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false); + //! Create and attach a bar series to the control + /** + @param bSecondaryHorizAxis + Specifies if the horizontal axis is the secondary axis or not. + @param bSecondaryVertAxis + Specifies if the vertical axis is the secondary axis or not. + @return The created chart bar series. + @remark The function will assert if the associated axes are not attached + to the control. + @see AttachCustomSerie for more info about the parameters of the function. + **/ + CChartBarSerie* CreateBarSerie(bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false); + //! Create and attach a candlestick series to the control + /** + @param bSecondaryHorizAxis + Specifies if the horizontal axis is the secondary axis or not. + @param bSecondaryVertAxis + Specifies if the vertical axis is the secondary axis or not. + @return The created chart candlestick series. + @remark The function will assert if the associated axes are not attached + to the control. + @see AttachCustomSerie for more info about the parameters of the function. + **/ + CChartCandlestickSerie* CreateCandlestickSerie(bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false); + //! Create and attach a gantt series to the control + /** + @param bSecondaryHorizAxis + Specifies if the horizontal axis is the secondary axis or not. + @param bSecondaryVertAxis + Specifies if the vertical axis is the secondary axis or not. + @return The created chart gantt series. + @remark The function will assert if the associated axes are not attached + to the control. + @see AttachCustomSerie for more info about the parameters of the function. + **/ + CChartGanttSerie* CreateGanttSerie(bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false); + //! Attaches a custom series to the chart + /** + You should only use this function if you want to attach a custom series + to the control. Otherwise, you should use the CreateXXXSerie helper functions. + The function will assert if the associated axes are not attached + to the control. + @param pNewSeries + The new series to be added. The control will take ownership of + the pointer, so dont't delete it yourself. + @param bSecondaryHorizAxis + Specifies if the associated horizontal axis is secondary or not. + If this value is false, the associated horizontal axis is the + bottom axis, otherwise it is the top axis. + @param bSecondaryVertAxis + Specifies if the associated vertical axis is secondary or not. + If this value is false, the associated vertical axis is the + left axis, otherwise it is the right axis. + **/ + void AttachCustomSerie(CChartSerie* pNewSeries, bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false); + //! Retrieves a specific series from the chart + /** + @param uSerieId + The Id of the series to retrieve + @return The series or NULL if uSerieId is not attributed. + **/ + CChartSerie* GetSerie(unsigned uSerieId) const; + //! Removes a specific series from the chart + /** + @param uSerieId + The Id of the series to be removed. + **/ + void RemoveSerie(unsigned uSerieId); + //! Removes all the series from the chart + void RemoveAllSeries(); + //! Returns the number of series in the chart + size_t GetSeriesCount() const; + + //! Create and attach a cross-hair cursor to the control + /** + A cross-hair cursor display a cross on the control and move accordingly + to the mouse. It is attached to an horizontal and a vertical axis. + @param bSecondaryHorizAxis + Specifies if the horizontal axis is the secondary axis or not. + @param bSecondaryVertAxis + Specifies if the vertical axis is the secondary axis or not. + @return The created cross-hair cursor. + @remark The function will assert if the associated axes are not attached + to the control. + **/ + CChartCrossHairCursor* CreateCrossHairCursor(bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false); + //! Create and attach a drag-line cursor to the control + /** + A drag-line cursor is a simple line (horizontal or vertical) that can be + dragged with the mouse by clicking on it. It is attached to a specific axis. + @param relatedAxis + The axis position to which the cursor is attached to. + @return The created drag-line cursor. + @remark The function will assert if the associated axis is not attached + to the control. + **/ + CChartDragLineCursor* CreateDragLineCursor(EAxisPos relatedAxis); + //! Attach a custom cursor to the control + /** + You should only use this function if you want to attach a custom cursor + to the control. Otherwise, you should use the CreateXXXCursor helper functions. + @param pCursor + The custom cursor to be attached to the control. + **/ + void AttachCustomCursor(CChartCursor* pCursor); + //! Removes a cursor with a specific Id from the control. + /** + The cursor Id can be retrieved on through the CChartCursor::GetCursorId function. + @param cursorId + The Id of the cursor to remove from the control. + **/ + void RemoveCursor(unsigned cursorId); + + //! Shows/hides the mouse cursor when it is over the plotting area. + void ShowMouseCursor(bool bShow); + + CChartAxis* GetBottomAxis() const; + CChartAxis* GetLeftAxis() const; + CChartAxis* GetTopAxis() const; + CChartAxis* GetRightAxis() const; + //! Returns a specific axis attached to the control + /** + If the specified axis does not exist, NULL is returned. + @param axisPos + The axis position (left, bottom, right or top). + **/ + CChartAxis* GetAxis(EAxisPos axisPos) const + { + return m_pAxes[axisPos]; + } + + //! Returns the type of the edge used as border. + UINT GetEdgeType() const { return EdgeType; } + //! Sets the edge type. + /** + @param NewEdge + The type of the edge. See the DrawEdge function in MSDN for + a list of the different types. + **/ + void SetEdgeType(UINT NewEdge) + { + EdgeType = NewEdge; + RefreshCtrl(); + } + + //! Returns the background color + COLORREF GetBackColor() const { return m_BackColor; } + //! Sets the background color. + void SetBackColor(COLORREF NewCol) + { + m_BackColor = NewCol; + m_bBackGradient = false; + RefreshCtrl(); + } + //! Returns the color of the plotting area's border + COLORREF GetBorderColor() const { return m_BorderColor; } + //! Sets the color of the plotting area's border + void SetBorderColor(COLORREF NewCol) { m_BorderColor = NewCol; RefreshCtrl(); } + //! Returns the color of the zoom rectangle + COLORREF GetZoomRectColor() const { return m_ZoomRectColor; } + //! Sets the color of the zoom rectangle + void SetZoomRectColor(COLORREF NewCol) { m_ZoomRectColor = NewCol; RefreshCtrl(); } + //! Sets a gradient background + /** + @param Col1 + The first gradient color + @param Col2 + The second gradient color + @param GradientType + The type of gradient used from Col1 to Col2. It can take the following values: + - gtHorizontal: a simple left-to-right gradient, from Col1 to Col2. + - gtVertical: a simple top-to-bottom gradient, from Col1 to Col2. + - gtHorizontalDouble: a left-to-middle-to-right gradient, with Col2 in the middle. + - gtVerticalDouble: a top-to-middle-to-bottom gradient, with Col2 in the middle. + **/ + void SetBackGradient(COLORREF Col1, COLORREF Col2, EGradientType GradientType); + + //! Enables/disables the pan feature + void SetPanEnabled(bool bEnabled) { m_bPanEnabled = bEnabled; } + //! Returns true if the pan feature is enabled + bool GetPanEnabled() const { return m_bPanEnabled; } + //! Enables/disables the zoom feature + void SetZoomEnabled(bool bEnabled) { m_bZoomEnabled = bEnabled; } + //! Returns true if the zoom feature is enabled + bool GetZoomEnabled() const { return m_bZoomEnabled; } + //! Undo all pan and zoom operations that were done on the chart + void UndoPanZoom(); + + //! Forces a refresh of the control. + /** + This function is used for internal purposes. + **/ + void RefreshCtrl(); + //! Enables/disables the refresh of the control + /** + This function is used when several settings have to be changed at the same + time on the control. This way we can avoid refreshing the control when it + is not needed. + @param bEnable + false to disable the refresh and true to re-enable the refresh. + **/ + void EnableRefresh(bool bEnable); + //! Creates the control dynamically. + /** + @param pParentWnd + Parent window of the control + @param rect + Position of the control + @param nID + ID of the control + @param dwStyle + Style of the control + **/ + int Create(CWnd* pParentWnd, const RECT& rect, UINT nID, DWORD dwStyle=WS_VISIBLE); + + //! Helper function to convert a date to a double value + static double DateToValue(const COleDateTime& Date); + //! Helper function to convert a double value to a date + static COleDateTime ValueToDate(double Value); + + //! Print the chart + /** + @param strTitle + The title of the print document. + @param pPrntDialog + A pointer to a CPrintDialog. + If NULL is passed, the default print dialog will be displayed. + **/ + virtual void Print(const TChartString& strTitle, CPrintDialog* pPrntDialog = NULL); + +#if _MFC_VER > 0x0600 + //! Saves the chart to an image file + /** + This function is not available for VC6 and earlier. + @param strFilename + The name of the file in which to save the image. + @param rect + The size of the image. If an empty rectangle is provided, the + size of the chart on screen will be used (this results in an identical + image as what is seen on the screen). + @param nBPP + The numbers of bits per pixel in the bitmap. Usually 4, 8, 16, 24, or 32. + @param guidFileType + The file type to save the image as. See the CImage::Save in MSDN + for more information. + **/ + void SaveAsImage(const TChartString& strFilename, const CRect& rect, + int nBPP, REFGUID guidFileType= GUID_NULL); +#endif + + //! Default constructor + CChartCtrl(); + //! Default destructor + virtual ~CChartCtrl(); + + //! Register a mouse listener with the control. + /** + This listener will be notified each time a mouse event occurs on the control. + @param pMouseListener + The mouse listener to register with this control. + **/ + void RegisterMouseListener(CChartMouseListener* pMouseListener) { m_pMouseListener = pMouseListener;} + + //! Tell the control to set the current series to the first series. + /** + This function is used with the GetNextSerie to iterate over all + series in the control. + **/ + void GoToFirstSerie(); + //! Returns the next series in the control. + /** + This function is used with the GoToFirstSerie to iterate over all + series in the control. First call GoToFirstSerie and then call this + function until it returns NULL to iterate over all series. + Warning: calling this function without calling GoToFirstSerie before + might lead to unpredicted results. The same if you add or remove + series between the call to GetFirstSerie and the call to GetNextSerie. + @return the next series or NULL if we already are at the last series. + **/ + CChartSerie* GetNextSerie(); + + //! Refreshes all the axes which are automatic for the screen. + void RefreshScreenAutoAxes(); + + // Generated message map functions +protected: + //{{AFX_MSG(CChartCtrl) + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); + afx_msg void OnRButtonDown(UINT nFlags, CPoint point); + afx_msg void OnRButtonUp(UINT nFlags, CPoint point); + afx_msg void OnRButtonDblClk(UINT nFlags, CPoint point); + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +protected: + virtual void OnBeginPrinting(CDC *pDC, CPrintInfo *pInfo); + virtual void OnPrint(CDC *pDC, CPrintInfo *pInfo); + virtual void OnEndPrinting(CDC *pDC, CPrintInfo *pInfo); + + // This function can be called to draw the chart + // on the screen or for printing. + virtual void DrawChart(CDC* pDC, CRect ChartRect); + virtual void DrawBackground(CDC* pDC, CRect ChartRect); + +private: + //! Register the window class used for this control + bool RegisterWindowClass(); + + //! Notifies the mouse listeners about a mouse event on the control. + /** + The function detects on which part of the control the event happened. + @param mouseEvent + The type of the mouse event + @param screenPoint + The screen point on which the event occured. + **/ + void SendMouseEvent(CChartMouseListener::MouseEvent mouseEvent, const CPoint& screenPoint) const; + + //! Specifies if the refresh is currently enabled or not. + int m_iEnableRefresh ; + //! Specifies if there is a pending refresh. + /** + If true, once EnableRefresh(true) is called, a refresh of the control + will be done. + **/ + bool m_bPendingRefresh; + //! Memory bitmap on which the chart background is drawn (axis, grid, title, ...) + CDC m_BackgroundDC; + //! Specifies if the memory bitmap has already been created. + bool m_bMemDCCreated; + + //! Specifies if the background is gradient or solid + bool m_bBackGradient; + //! First gradient color for the background + COLORREF m_BackGradientCol1; + //! Second gradient color for the background + COLORREF m_BackGradientCol2; + //! The gradient type used for the background + EGradientType m_BackGradientType; + //! The background color (if no gradient used) + COLORREF m_BackColor; + //! The border color + COLORREF m_BorderColor; + //! The type of edge + UINT EdgeType; + + //! Zone in wich the series will be plotted + CRect m_PlottingRect; + + typedef std::map TSeriesMap; + //! Map containing all the series added to the chart. + TSeriesMap m_mapSeries; + //! The four axis of the control. + CChartAxis* m_pAxes[4]; + + //! The chart legend + CChartLegend* m_pLegend; + //! The chart titles + CChartTitle* m_pTitles; + + //! Specifies if the mouse panning is enabled + bool m_bPanEnabled; + //! Specifies if the right mouse button is currently pressed + bool m_bRMouseDown; + //! The point on which the panning started + CPoint m_PanAnchor; + + //! Specifies if the zoom is enabled + bool m_bZoomEnabled; + //! Specifies if the left mouse button is currently pressed + bool m_bLMouseDown; + //! The rectangle of the zoom area + CRect m_rectZoomArea; + //! The color of the zoom rectangle + COLORREF m_ZoomRectColor; + + //! Specifies if the toolbars have already been created + bool m_bToolBarCreated; + + //! The font used for printing + CFont m_PrinterFont; + //! Page size in chartctrl units. + CSize m_LogicalPageSize; + //! Page size in device units. + CSize m_PaperSize; + + typedef std::map TCursorMap; + //! The map containing all the cursors + TCursorMap m_mapCursors; + + //! The mouse listener registered with this control + CChartMouseListener* m_pMouseListener; + + //! Specifies if the mouse is visible when over the plotting area. + bool m_bMouseVisible; + + typedef TSeriesMap::const_iterator TSeriesMapIter; + //! The iterator of the current series + TSeriesMapIter m_currentSeries; +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + diff --git a/ChartDemo/ChartCtrl/ChartCtrl_source.zip b/ChartDemo/ChartCtrl/ChartCtrl_source.zip new file mode 100644 index 0000000000000000000000000000000000000000..299c614f463a76411f161d770cf1e26395030f8c GIT binary patch literal 108508 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�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 literal 0 HcmV?d00001 diff --git a/ChartDemo/ChartCtrl/ChartCursor.cpp b/ChartDemo/ChartCtrl/ChartCursor.cpp new file mode 100644 index 0000000..2ab64c8 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartCursor.cpp @@ -0,0 +1,56 @@ +/* + * + * ChartCursor.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#include "stdafx.h" +#include "ChartCursor.h" +#include "ChartCtrl.h" + +unsigned CChartCursor::m_uNextFreeId = 0; + +CChartCursor::CChartCursor(CChartCtrl* pParent) + : m_colCursor(RGB(0,0,0)), m_pParentCtrl(pParent), m_uCursorId(0), + m_lstListeners() +{ + m_uCursorId = m_uNextFreeId; + m_uNextFreeId++; +} + +CChartCursor::~CChartCursor() +{ +} + +void CChartCursor::SetColor(COLORREF cursorColor) +{ + m_colCursor = cursorColor; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartCursor::RegisterListener(CChartCursorListener* pListener) +{ + m_lstListeners.push_back(pListener); +} + +void CChartCursor::CursorMoved(double newXValue, double newYValue) +{ + TListenerList::iterator iter = m_lstListeners.begin(); + for (iter; iter!=m_lstListeners.end(); iter++) + (*iter)->OnCursorMoved(this, newXValue, newYValue); +} diff --git a/ChartDemo/ChartCtrl/ChartCursor.h b/ChartDemo/ChartCtrl/ChartCursor.h new file mode 100644 index 0000000..010c555 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartCursor.h @@ -0,0 +1,125 @@ +/* + * + * ChartCursor.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#ifndef _CHARTCURSOR_H_ +#define _CHARTCURSOR_H_ + +#include + +class CChartCtrl; +class CChartCursor; + +//! Interface to implement in order to be notified about a cursor movement. +/** + This class must be overriden and registered with a CChartCursor by + calling RegisterListener. +**/ +class CChartCursorListener +{ +public: + //! Default constructor + CChartCursorListener() { } + //! Destructor + virtual ~CChartCursorListener() { } + + //! Pure virtual function to implement in order to be notified about a cursor movement. + /** + Note that not all cursor types have an X and a Y value, in which case, only + the relevant information is passed, the other value will be 0. + @param pCursor + The cursor which was moved + @param xValue + The cursor xValue + @param yValue + The cursor yValue + **/ + virtual void OnCursorMoved(CChartCursor* pCursor, double xValue, double yValue) = 0; +}; + +//! Base class for cursors which can be added to the chart control. +/** + This class must be overriden for specific cursor types. This is already done + for a cross-hair cursor and a dragline cursor. Each cursor is assigned an Id + when it is added to the control. +**/ +class CChartCursor +{ + friend CChartCtrl; + +public: + //! Sets the cursor color. + void SetColor(COLORREF cursorColor); + //! Retrieves the cursor Id. + unsigned GetCursorId() const { return m_uCursorId; } + + //! Registers a cursor listener with this cursor. + void RegisterListener(CChartCursorListener* pListener); + +protected: + //! Default constructor + CChartCursor(CChartCtrl* pParent); + //! Default destructor + virtual ~CChartCursor(); + + //! Pure virtual function that is called when the mouse moved on the plot area. + /** + This function must be overriden by child classes to take appropriate + actions on the mouse move event. + **/ + virtual void OnMouseMove(CPoint mousePoint) = 0; + //! Virtual function that is called when the left mouse button is pressed. + /** + This function can be overriden by child classes to take appropriate + actions on the mouse click event. + **/ + virtual void OnMouseButtonDown(CPoint /*mousePoint*/) { } + //! Virtual function that is called when the left mouse button is released. + /** + This function can be overriden by child classes to take appropriate + actions on the mouse click event. + **/ + virtual void OnMouseButtonUp(CPoint /*mousePoint*/) { } + + //! Pure virtual function that draws the cursor. + virtual void Draw(CDC* pDC) = 0; + //! Function that is called by the child classes when the cursor has been moved. + /** + This will notify all the listeners registered with the cursor. + **/ + void CursorMoved(double newXValue, double newYValue); + + + //! The color of the cursor. + COLORREF m_colCursor; + //! The parent charting control. + CChartCtrl* m_pParentCtrl; + + //! Static variable holding the next free cursor Id. + static unsigned m_uNextFreeId; + //! The Id of this curosr. + unsigned m_uCursorId; + + typedef std::list TListenerList; + //! List of all listeners registered with this cursor. + TListenerList m_lstListeners; +}; + +#endif // _CHARTCURSOR_H_ diff --git a/ChartDemo/ChartCtrl/ChartDateTimeAxis.cpp b/ChartDemo/ChartCtrl/ChartDateTimeAxis.cpp new file mode 100644 index 0000000..7cc3b48 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartDateTimeAxis.cpp @@ -0,0 +1,411 @@ +/* + * + * ChartDateTimeAxis.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + */ + +#include "stdafx.h" +#include "ChartDateTimeAxis.h" +#include "ChartCtrl.h" +#include +#include +#include +#include + +using namespace std; + +CChartDateTimeAxis::CChartDateTimeAxis() + : CChartAxis(), m_strDTTickFormat(), + m_bAutoTickFormat(true), m_BaseInterval(tiDay), + m_iDTTickIntervalMult(1), m_dFirstTickValue(0) +{ + m_ReferenceTick.SetDate(2000,1,1); +} + +CChartDateTimeAxis::~CChartDateTimeAxis() +{ +} + + +void CChartDateTimeAxis::SetTickIncrement(bool bAuto, + TimeInterval Interval, + int Multiplier) +{ + m_bAutoTicks = bAuto; + if (!m_bAutoTicks) + { + m_BaseInterval = Interval; + m_iDTTickIntervalMult = Multiplier; + } +} + +void CChartDateTimeAxis::SetTickLabelFormat(bool bAutomatic, + const TChartString& strFormat) +{ + m_bAutoTickFormat = bAutomatic; + m_strDTTickFormat = strFormat; + m_pParentCtrl->RefreshCtrl(); +} + +double CChartDateTimeAxis::GetFirstTickValue() const +{ + double dRetVal = m_dFirstTickValue; + if (m_bDiscrete) + { + COleDateTime dtTick((DATE)m_dFirstTickValue); + COleDateTimeSpan dtSpan; + switch (m_BaseInterval) + { + case tiSecond: + dtSpan.SetDateTimeSpan(0,0,0,m_iDTTickIntervalMult); + dtTick -= dtSpan; + break; + case tiMinute: + dtSpan.SetDateTimeSpan(0,0,m_iDTTickIntervalMult,0); + dtTick -= dtSpan; + break; + case tiHour: + dtSpan.SetDateTimeSpan(0,m_iDTTickIntervalMult,0,0); + dtTick -= dtSpan; + break; + case tiDay: + dtSpan.SetDateTimeSpan(m_iDTTickIntervalMult,0,0,0); + dtTick -= dtSpan; + break; + case tiMonth: + dtTick = AddMonthToDate(dtTick,-m_iDTTickIntervalMult); + break; + case tiYear: + dtTick = AddMonthToDate(dtTick,-12*m_iDTTickIntervalMult); + break; + } + } + return dRetVal; + +} + +bool CChartDateTimeAxis::GetNextTickValue(double dCurrentTick, double& dNextTick) const +{ + if (m_MinValue == m_MaxValue) + return false; + + COleDateTime dtTick((DATE)dCurrentTick); + COleDateTimeSpan dtSpan; + switch (m_BaseInterval) + { + case tiSecond: + dtSpan.SetDateTimeSpan(0,0,0,m_iDTTickIntervalMult); + dtTick += dtSpan; + break; + case tiMinute: + dtSpan.SetDateTimeSpan(0,0,m_iDTTickIntervalMult,0); + dtTick += dtSpan; + break; + case tiHour: + dtSpan.SetDateTimeSpan(0,m_iDTTickIntervalMult,0,0); + dtTick += dtSpan; + break; + case tiDay: + dtSpan.SetDateTimeSpan(m_iDTTickIntervalMult,0,0,0); + dtTick += dtSpan; + break; + case tiMonth: + dtTick = AddMonthToDate(dtTick,m_iDTTickIntervalMult); + break; + case tiYear: + dtTick = AddMonthToDate(dtTick,12*m_iDTTickIntervalMult); + break; + } + + dNextTick = (DATE)dtTick; + if (dNextTick <= m_MaxValue) + return true; + else + return false; +} + +TChartString CChartDateTimeAxis::GetTickLabel(double TickValue) const +{ + COleDateTime tickTime((DATE)TickValue); + TChartString strLabel = tickTime.Format(m_strDTTickFormat.c_str()); + return strLabel; +} + +long CChartDateTimeAxis::ValueToScreenDiscrete(double dValue) const +{ + // In discrete mode, all values between two ticks relates + // to the middle of the interval (there's no other values than + // the tick values). + double tickAfter; + double tickBefore = GetTickBeforeVal(dValue); + GetNextTickValue(tickBefore, tickAfter); + + long tickPosBefore = ValueToScreenStandard(tickBefore); + long tickPosAfter = ValueToScreenStandard(tickAfter); + return tickPosBefore + (tickPosAfter-tickPosBefore)/2; +} + +long CChartDateTimeAxis::GetTickPos(double TickVal) const +{ + // The tick is always at the same position, + // even if the axis is discrete. + return ValueToScreenStandard(TickVal); +} + +COleDateTime CChartDateTimeAxis::AddMonthToDate(const COleDateTime& Date, + int iMonthsToAdd) const +{ + COleDateTime newDate; + int nMonths = Date.GetMonth()-1 + iMonthsToAdd; + int nYear = Date.GetYear() + nMonths/12;; + // We can 'add' a negative number of months + if (nMonths<0) + { + nYear = Date.GetYear() - (-nMonths)/12; + nMonths += (-nMonths)/12 * 12; + } + + newDate.SetDateTime(nYear,nMonths%12+1,Date.GetDay(),Date.GetHour(), + Date.GetMinute(),Date.GetSecond()); + return newDate; +} + +void CChartDateTimeAxis::RefreshTickIncrement() +{ + if (!m_bAutoTicks) + return; + + if (m_MaxValue == m_MinValue) + { + m_iDTTickIntervalMult = 1; + return; + } + + int PixelSpace; + if (m_bIsHorizontal) + PixelSpace = 60; + else + PixelSpace = 20; + + int MaxTickNumber = (int)fabs((m_EndPos-m_StartPos)/PixelSpace * 1.0); + if (MaxTickNumber == 0) + MaxTickNumber = 1; + + COleDateTime StartDate(m_MinValue); + COleDateTime EndDate(m_MaxValue); + + COleDateTimeSpan minTickInterval = (EndDate - StartDate)/MaxTickNumber; + double Seconds = minTickInterval.GetTotalSeconds(); + double Minutes = minTickInterval.GetTotalMinutes(); + double Hours = minTickInterval.GetTotalHours(); + double Days = minTickInterval.GetTotalDays(); + if (Seconds < 60) + { + m_BaseInterval = tiSecond; + if (Seconds > 30) + { + m_BaseInterval = tiMinute; + m_iDTTickIntervalMult = 1; + } + else if (Seconds > 10) + m_iDTTickIntervalMult = 30; + else if (Seconds > 5) + m_iDTTickIntervalMult = 10; + else if (Seconds > 2) + m_iDTTickIntervalMult = 5; + else + m_iDTTickIntervalMult = 1; + } + else if (Minutes < 60) + { + m_BaseInterval = tiMinute; + if (Minutes > 30) + { + m_BaseInterval = tiHour; + m_iDTTickIntervalMult = 1; + } + else if (Minutes > 10) + m_iDTTickIntervalMult = 30; + else if (Minutes > 5) + m_iDTTickIntervalMult = 10; + else if (Minutes > 2) + m_iDTTickIntervalMult = 5; + else + m_iDTTickIntervalMult = 2; + } + else if (Hours < 24) + { + m_BaseInterval = tiHour; + if (Hours > 12) + { + m_BaseInterval = tiDay; + m_iDTTickIntervalMult = 1; + } + else if (Hours > 6) + m_iDTTickIntervalMult = 12; + else if (Hours > 2) + m_iDTTickIntervalMult = 6; + else + m_iDTTickIntervalMult = 2; + } + else if (Days < 31) + { + m_BaseInterval = tiDay; + if (Days > 7) + { + m_BaseInterval = tiMonth; + m_iDTTickIntervalMult = 1; + } + else if (Days > 2) + { + m_BaseInterval = tiDay; + m_iDTTickIntervalMult = 7; + } + else + m_iDTTickIntervalMult = 2; + } + else if (Days < 365) + { + m_BaseInterval = tiMonth; + if (Days > 186) // Approx 6 months + { + m_BaseInterval = tiYear; + m_iDTTickIntervalMult = 1; + } + else if (Days > 124) + m_iDTTickIntervalMult = 6; + else if (Days > 62) + m_iDTTickIntervalMult = 4; + else + m_iDTTickIntervalMult = 2; + } + else + { + m_BaseInterval = tiYear; + m_iDTTickIntervalMult = (int)Days/365 + 1; + } +} + +void CChartDateTimeAxis::RefreshFirstTick() +{ + m_dFirstTickValue = GetTickBeforeVal(m_MinValue); + if (m_bAutoTickFormat) + RefreshDTTickFormat(); +} + +void CChartDateTimeAxis::SetReferenceTick(COleDateTime referenceTick) +{ + m_ReferenceTick = referenceTick; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartDateTimeAxis::RefreshDTTickFormat() +{ + switch (m_BaseInterval) + { + case tiSecond: + m_strDTTickFormat = _T("%H:%M:%S"); + break; + case tiMinute: + m_strDTTickFormat = _T("%H:%M"); + break; + case tiHour: + m_strDTTickFormat = _T("%H:00"); + break; + case tiDay: + m_strDTTickFormat = _T("%d %b"); + break; + case tiMonth: + m_strDTTickFormat = _T("%b %Y"); + break; + case tiYear: + m_strDTTickFormat = _T("%Y"); + break; + } +} + +double CChartDateTimeAxis::GetTickBeforeVal(double dValue) const +{ + double precision = 0.0000000001; + if (dValue < 0) + precision = -0.0000000001; + + COleDateTime tickBefore; + COleDateTime valueTime = COleDateTime(DATE(dValue+precision)); + COleDateTimeSpan dtSpan = valueTime - m_ReferenceTick; + switch (m_BaseInterval) + { + case tiSecond: + { + int totalSecs = (int)dtSpan.GetTotalSeconds(); + totalSecs = (totalSecs/m_iDTTickIntervalMult) * m_iDTTickIntervalMult; + int Days = totalSecs/86400; // 86400 seconds in one day + int Hours = (totalSecs%86400)/3600; // 3600 seconds in one hour + int Minutes = ((totalSecs%86400)%3600)/60; // 60 seconds in one minute + int Seconds = ((totalSecs%86400)%3600)%60; + dtSpan.SetDateTimeSpan(Days, Hours, Minutes, Seconds); + tickBefore = m_ReferenceTick + dtSpan; + } + break; + case tiMinute: + { + int totalMinutes = (int)dtSpan.GetTotalMinutes(); + totalMinutes = (totalMinutes/m_iDTTickIntervalMult) * m_iDTTickIntervalMult; + int Days = totalMinutes/1440; // 1440 minutes in one day + int Hours = (totalMinutes%1440)/60; // 60 minutes in one hour + int Minutes = (totalMinutes%1440)%60; + dtSpan.SetDateTimeSpan(Days, Hours, Minutes, 0); + tickBefore = m_ReferenceTick + dtSpan; + } + break; + case tiHour: + { + int totalHours = (int)dtSpan.GetTotalHours(); + totalHours = (totalHours/m_iDTTickIntervalMult) * m_iDTTickIntervalMult; + int Days = totalHours/24; // 24 hours in one day + int Hours = totalHours%24; + dtSpan.SetDateTimeSpan(Days, Hours, 0, 0); + tickBefore = m_ReferenceTick + dtSpan; + } + break; + case tiDay: + { + int totalDays = (int)dtSpan.GetTotalDays(); + totalDays = (totalDays/m_iDTTickIntervalMult) * m_iDTTickIntervalMult; + dtSpan.SetDateTimeSpan(totalDays, 0, 0, 0); + tickBefore = m_ReferenceTick + dtSpan; + } + break; + case tiMonth: + { + int yearDiff = valueTime.GetYear() - m_ReferenceTick.GetYear(); + int monthDiff = valueTime.GetMonth() - m_ReferenceTick.GetMonth(); + int totalMonths = ((yearDiff*12+monthDiff)/m_iDTTickIntervalMult) * m_iDTTickIntervalMult; + tickBefore = AddMonthToDate(m_ReferenceTick,totalMonths); + } + break; + case tiYear: + { + int yearDiff = valueTime.GetYear() - m_ReferenceTick.GetYear(); + int year = ((yearDiff)/m_iDTTickIntervalMult) * m_iDTTickIntervalMult; + tickBefore = AddMonthToDate(m_ReferenceTick,year*12); + } + break; + } + + return (DATE)tickBefore; +} diff --git a/ChartDemo/ChartCtrl/ChartDateTimeAxis.h b/ChartDemo/ChartCtrl/ChartDateTimeAxis.h new file mode 100644 index 0000000..dcf7330 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartDateTimeAxis.h @@ -0,0 +1,150 @@ +/* + * + * ChartDateTimeAxis.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#ifndef _CHARTDATETIMEAXIS_H_ +#define _CHARTDATETIMEAXIS_H_ + +#include "ChartAxis.h" +#include "ChartString.h" + +//! A specialization of the CChartAxis class for displaying date and time data. +class CChartDateTimeAxis : public CChartAxis +{ + friend CChartCtrl; + +public: + //! Enum listing the different base intervals. + enum TimeInterval + { + tiSecond, + tiMinute, + tiHour, + tiDay, + tiMonth, + tiYear + }; + + //! Sets the tick increment. + /** + The tick increment is the value between two adjacents + ticks on the axis. In case of a date time axis, the interval + is specified by a time period because this interval might not + be constant (for instance, if a tick interval of one month is + specified, the distance between two adjacents ticks is not + constant: it depends on the number of days in the month). + The full tick interval is made of a base interval (day, month, + hour, ...) and a multiplier, that is applied to this base interval. + So, for an interval of three months between two ticks, you have to + specify tiMonth for the interval and 3 for the multiplier. + @param bAuto + Specifies if the tick increment is automatically calculated. + @param Interval + The base interval. + @param Multiplier + The multiplier applied to the base interval. + **/ + void SetTickIncrement(bool bAuto, TimeInterval Interval, int Multiplier); + //! Sets the format of the tick labels. + /** + @param bAutomatic + Specifies if the format is calculated automatically. + @param strFormat + The format to apply to the tick label if bAutomatic is false. +
Check the documentation of the COleDateTime::Format function on + MSDN for more information about the format string. + **/ + void SetTickLabelFormat(bool bAutomatic, const TChartString& strFormat); + //! Sets the reference tick. + /** + The reference tick is a date/time which specifies a tick which should + always be displayed on the axis. This is needed when the tick + interval multiplier is not 1 (e.g. the interval between two ticks is 3 + months). In that specific case, there is no way for the control to know + which ticks should be displayed (in our example, the chart doesn't know + if the first tick will be january, february or march). This is particularly + annoying when the axis is panned (in that case, if we always take the first + month on the axis as first tick, the ticks will always switch from one month + to another). By having a refence tick, this forces the control to calculate + all tick intervals based on this reference. It is set to January 1st 2000 by + default. + **/ + void SetReferenceTick(COleDateTime referenceTick); + +private: + //! Default constructor + CChartDateTimeAxis(); + //! Default destructor + ~CChartDateTimeAxis(); + + double GetFirstTickValue() const; + bool GetNextTickValue(double dCurrentTick, double& dNextTick) const; + TChartString GetTickLabel(double TickValue) const; + long ValueToScreenDiscrete(double Value) const; + long GetTickPos(double TickVal) const; + + void RefreshTickIncrement(); + void RefreshFirstTick(); + //! Forces a refresh of the date/time tick label format + void RefreshDTTickFormat(); + + //! Add a number of months to a date. + /** + The function takes care of 'overflow' (total number + of months higher than 12) error when adding the months. + @param Date + The date to which months will be added. + @param iMonthsToAdd + The number of months to add to the date. + @return the resulting date. + **/ + COleDateTime AddMonthToDate(const COleDateTime& Date, + int iMonthsToAdd) const; + + double GetTickBeforeVal(double dValue) const; + + //! Format of the date/time tick labels + TChartString m_strDTTickFormat; + //! Specifies if the tick labels format is automatic + bool m_bAutoTickFormat; + //! Specifies the base time interval for ticks + /** + This specifies an base interval in sec, min, hour, + day, month or year. The total tick increment is + a mutliple of this base interval (specified by + m_iDTTickIntervalMult). E.g: 2 days + **/ + TimeInterval m_BaseInterval; + //! Specifies the multiplicator for the base interval + /** + This multiplies the base interval for the ticks, resulting + in something like 3 minutes (a multiplicator of 1 can also + be specified). + **/ + int m_iDTTickIntervalMult; + + //! Caches the value of the first tick. + double m_dFirstTickValue; + + //! The reference tick. See the SetReferenceTick function for details. + COleDateTime m_ReferenceTick; +}; + +#endif // _CHARTDATETIMEAXIS_H_ \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartDragLineCursor.cpp b/ChartDemo/ChartCtrl/ChartDragLineCursor.cpp new file mode 100644 index 0000000..6eb6dcf --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartDragLineCursor.cpp @@ -0,0 +1,103 @@ +/* + * + * ChartDragLineCursor.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#include "stdafx.h" +#include "ChartDragLineCursor.h" +#include "ChartCtrl.h" + +CChartDragLineCursor::CChartDragLineCursor(CChartCtrl* pParent, + CChartAxis* pRelatedAxis) + : CChartCursor(pParent), m_pRelatedAxis(pRelatedAxis), m_lPosition(0), + m_bDragged(false) +{ +} + +CChartDragLineCursor::~CChartDragLineCursor() +{ +} + +void CChartDragLineCursor::Draw(CDC* pDC) +{ + CPen NewPen(PS_SOLID,1,m_colCursor); + CPen* pOldPen = pDC->SelectObject(&NewPen); + + CRect plottingRect = m_pParentCtrl->GetPlottingRect(); + + if (m_pRelatedAxis->IsHorizontal()) + { + pDC->MoveTo(m_lPosition, plottingRect.top); + pDC->LineTo(m_lPosition, plottingRect.bottom); + } + else + { + pDC->MoveTo(plottingRect.left, m_lPosition); + pDC->LineTo(plottingRect.right, m_lPosition); + } + + pDC->SelectObject(pOldPen); + NewPen.DeleteObject(); +} + +void CChartDragLineCursor::OnMouseButtonDown(CPoint mousePoint) +{ + long position = 0; + if (m_pRelatedAxis->IsHorizontal()) + position = mousePoint.x; + else + position = mousePoint.y; + + if ( (position >= m_lPosition-3) && + (position <= m_lPosition+3) ) + { + m_bDragged = true; + } +} + +void CChartDragLineCursor::OnMouseButtonUp(CPoint /*mousePoint*/) +{ + m_bDragged = false; +} + +void CChartDragLineCursor::OnMouseMove(CPoint mousePoint) +{ + if (!m_bDragged) + return; + + double XVal = 0; + double YVal = 0; + if (m_pRelatedAxis->IsHorizontal()) + { + m_lPosition = mousePoint.x; + XVal = m_pRelatedAxis->ScreenToValue(m_lPosition); + } + else + { + m_lPosition = mousePoint.y; + YVal = m_pRelatedAxis->ScreenToValue(m_lPosition); + } + + CursorMoved(XVal, YVal); +} + +void CChartDragLineCursor::SetPosition(double dPosition) +{ + m_lPosition = m_pRelatedAxis->ValueToScreen(dPosition); +} diff --git a/ChartDemo/ChartCtrl/ChartDragLineCursor.h b/ChartDemo/ChartCtrl/ChartDragLineCursor.h new file mode 100644 index 0000000..9a07270 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartDragLineCursor.h @@ -0,0 +1,72 @@ +/* + * + * ChartDragLineCursor.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#ifndef _CHARTDRAGLINECURSOR_H_ +#define _CHARTDRAGLINECURSOR_H_ + +#include "ChartCursor.h" + +class CChartAxis; + +//! Specialization of a CChartCursor class for a dragline cursor. +/** + A dragline cursor is a simple vertical or horizontal line associated + with a specific axis. The line can be moved if the user clicks on the + line (and keeps the button pressed) and moves the mouse. Once the mouse + button is released, the line doesn't move anymore.
+ To create a dragline cursor, call the CreateDragLineCursor from the + CChartCtrl class. +**/ +class CChartDragLineCursor : public CChartCursor +{ + friend CChartCtrl; + +public: + //! Sets the position (by value) of the cursor. + void SetPosition(double dPosition); + +protected: + //! Called when the mouse is moved over the plot area. + void OnMouseMove(CPoint mousePoint); + //! Called when the mouse button is pressed over the plot area. + void OnMouseButtonDown(CPoint mousePoint); + //! Called when the mouse button is released over the plot area. + void OnMouseButtonUp(CPoint mousePoint); + + //! Draw the cursor. + void Draw(CDC* pDC); + +private: + //! Constructor + CChartDragLineCursor(CChartCtrl* pParent, CChartAxis* pRelatedAxis); + //! Destructor + ~CChartDragLineCursor(); + + //! The axis to which this cursor is attached. + CChartAxis* m_pRelatedAxis; + + //! flag specifying if the cursor is currently being dragged. + bool m_bDragged; + //! The current screen position of the cursor. + long m_lPosition; +}; + +#endif // _CHARTDRAGLINECURSOR_H_ \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartFont.cpp b/ChartDemo/ChartCtrl/ChartFont.cpp new file mode 100644 index 0000000..deae84f --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartFont.cpp @@ -0,0 +1,145 @@ +/* + * + * ChartFont.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + */ + +#include "stdafx.h" +#include "ChartFont.h" + +CChartFont::CChartFont(const TChartString& strFaceName, int iPointSize) + : m_strFaceName(strFaceName), m_iPointSize(iPointSize), m_bItalic(false), + m_bBold(false), m_bUnderline(false), m_bVertical(false), m_Font(), m_bDirty(true), + m_pOldFont(NULL) +{ +} + +CChartFont::CChartFont(const CChartFont& copy) +{ + *this = copy; +} + +CChartFont::CChartFont() + : m_strFaceName(_T("Microsoft Sans Serif")), m_iPointSize(100), m_bItalic(false), + m_bBold(false), m_bUnderline(false), m_bVertical(false), m_Font(), m_bDirty(true), + m_pOldFont(NULL) +{ +} + +CChartFont::~CChartFont() +{ + m_Font.DeleteObject(); +} + +/*CFont* CChartFont::GetFont(CDC* pDC) +{ + if (!m_pFont) + m_pFont = new CFont(); + + if (m_bDirty) + { + LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); + lf.lfHeight = m_iPointSize; + _tcscpy_s(lf.lfFaceName,LF_FACESIZE-1 , m_strFaceName.c_str()); + lf.lfItalic = m_bItalic; + lf.lfUnderline = m_bUnderline; + if (m_bBold) + lf.lfWeight = FW_BOLD; + else + lf.lfWeight = FW_NORMAL; + + m_pFont->CreatePointFontIndirect(&lf, pDC); + } + + return m_pFont; +}*/ + +void CChartFont::operator=(const CChartFont& objectSrc) +{ + m_strFaceName = objectSrc.m_strFaceName; + m_iPointSize = objectSrc.m_iPointSize; + + m_bItalic = objectSrc.m_bItalic; + m_bBold = objectSrc.m_bBold; + m_bUnderline = objectSrc.m_bUnderline; + m_bVertical = objectSrc.m_bVertical; + + m_bDirty = true; +} + +void CChartFont::SelectFont(CDC* pDC) const +{ + if (m_bDirty) + { + LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); + lf.lfHeight = m_iPointSize; +#ifdef _CRT_INSECURE_DEPRECATE + _tcscpy_s(lf.lfFaceName,LF_FACESIZE-1 , m_strFaceName.c_str()); +#else + _tcscpy(lf.lfFaceName, m_strFaceName.c_str()); +#endif + lf.lfItalic = m_bItalic; + lf.lfUnderline = m_bUnderline; + if (m_bBold) + lf.lfWeight = FW_BOLD; + else + lf.lfWeight = FW_NORMAL; + + if (m_bVertical) + { + lf.lfOrientation = 900; + lf.lfEscapement = 900; + } + + m_Font.DeleteObject(); + m_Font.CreatePointFontIndirect(&lf, pDC); + m_bDirty = false; + } + + m_pOldFont = pDC->SelectObject(&m_Font); +} + +void CChartFont::UnselectFont(CDC* pDC) const +{ + ASSERT(m_pOldFont); + pDC->SelectObject(m_pOldFont); + m_pOldFont = NULL; +} + +void CChartFont::SetFont(const TChartString& strFaceName, + int iPointSize, + bool bItalic, + bool bBold, + bool bUnderline) +{ + m_strFaceName = strFaceName; + m_iPointSize = iPointSize; + + m_bItalic = bItalic; + m_bBold = bBold; + m_bUnderline = bUnderline; + + m_bDirty = true; +} + +void CChartFont::SetVertical(bool bVertical) +{ + m_bVertical = bVertical; + m_bDirty = true; +} diff --git a/ChartDemo/ChartCtrl/ChartFont.h b/ChartDemo/ChartCtrl/ChartFont.h new file mode 100644 index 0000000..6f689d3 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartFont.h @@ -0,0 +1,111 @@ +/* + * + * ChartFont.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#ifndef _CHARTFONT_H_ +#define _CHARTFONT_H_ + +#include "ChartString.h" +#include + +//! Wrapper class for fonts with advanced properties (italic, bold or underlined). +class CChartFont +{ +public: + //! Copy constructor. + CChartFont(const CChartFont& copy); + //! Constructor + /** + @param strFaceName + The font face name + @param iPointSize + The font point size + **/ + CChartFont(const TChartString& strFaceName, int iPointSize); + //! Default constructor + /** + Construct a font with the "Microsoft Sans Serif" face name and + with a point size of 100. + **/ + CChartFont(); + //! Destructor + ~CChartFont(); + + //! Sets the font with extended properties. + /** + @param strFaceName + The font face name + @param iPointSize + The font point size + @param bItalic + Specifies if the text is in italic + @param bBold + Specifies if the text is in bold + @param bUnderline + Specifies if the text is underlined + **/ + void SetFont(const TChartString& strFaceName, int iPointSize, + bool bItalic=false, bool bBold=false, bool bUnderline=false); + + //! Select this font in the device context passed in argument. + /** + This function stores the current font selected in the DC to + set it back when calling UnselectFont. This function is mainly + used internally. + **/ + void SelectFont(CDC* pDC) const; + //! Reset the font to its original in the device context. + void UnselectFont(CDC* pDC) const; + + //! Sets the text in vertical mode. + /** + This function is mainly used internally. + **/ + void SetVertical(bool bVertical); + + //! Assignement operator. + void operator=(const CChartFont& objectSrc); + +private: + //! The font face name + TChartString m_strFaceName; + //! The font point size + int m_iPointSize; + + //! Specifies if the font is italic + bool m_bItalic; + //! Specifies if the font is bold + bool m_bBold; + //! Specifies if the font is underlined + bool m_bUnderline; + + //! Specifies if the font is vertical + bool m_bVertical; + + //! Caches the current font + mutable CFont m_Font; + //! Specifies if the font information has been modified + mutable bool m_bDirty; + + //! The old font which is stored when calling SelectFont + mutable CFont* m_pOldFont; +}; + +#endif // _CHARTFONT_H_ \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartGanttSerie.cpp b/ChartDemo/ChartCtrl/ChartGanttSerie.cpp new file mode 100644 index 0000000..1e34103 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartGanttSerie.cpp @@ -0,0 +1,228 @@ +/* + * + * ChartGanttSerie.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#include "stdafx.h" +#include "ChartGanttSerie.h" +#include "ChartCtrl.h" + +CChartGanttSerie::CChartGanttSerie(CChartCtrl* pParent) + : CChartSerieBase(pParent), m_iBarWidth(10), m_iBorderWidth(1), + m_BorderColor(RGB(0,0,0)), m_bGradient(true), + m_GradientColor(RGB(255,255,255)), m_GradientType(gtHorizontalDouble) +{ + m_bShadow = true; + this->SetSeriesOrdering(poYOrdering); +} + +CChartGanttSerie::~CChartGanttSerie() +{ +} + +void CChartGanttSerie::AddPoint(double StartTime, double EndTime, double YValue) +{ + SChartGanttPoint newPoint(StartTime, EndTime, YValue); + CChartSerieBase::AddPoint(newPoint); +} + +bool CChartGanttSerie::IsPointOnSerie(const CPoint& screenPoint, + unsigned& uIndex) const +{ + uIndex = INVALID_POINT; + if (!m_bIsVisible) + return false; + + unsigned uFirst=0, uLast=0; + if (!GetVisiblePoints(uFirst,uLast)) + return false; + if (uFirst>0) + uFirst--; + if (uLastGetSafeHdc()) + return; + + //Draw bar: + CBrush BorderBrush(m_BorderColor); + pDC->FillRect(rectBitmap,&BorderBrush); + + CRect FillRect(rectBitmap); + CBrush FillBrush(m_SerieColor); + FillRect.DeflateRect(m_iBorderWidth,m_iBorderWidth); + if (m_bGradient) + { + CChartGradient::DrawGradient(pDC,FillRect,m_SerieColor,m_GradientColor,m_GradientType); + } + else + { + pDC->FillRect(FillRect,&FillBrush); + } +} + +void CChartGanttSerie::Draw(CDC* pDC) +{ + if (!m_bIsVisible) + return; + if (!pDC->GetSafeHdc()) + return; + + unsigned uFirst=0, uLast=0; + if (!GetVisiblePoints(uFirst,uLast)) + return; + + CRect TempClipRect(m_PlottingRect); + TempClipRect.DeflateRect(1,1); + pDC->SetBkMode(TRANSPARENT); + pDC->IntersectClipRect(TempClipRect); + + CBrush BorderBrush(m_BorderColor); + CBrush FillBrush(m_SerieColor); + //Draw all points that haven't been drawn yet + for (m_uLastDrawnPoint;m_uLastDrawnPoint<(int)GetPointsCount();m_uLastDrawnPoint++) + { + CRect BarRect = GetBarRectangle(m_uLastDrawnPoint); + DrawBar(pDC, &FillBrush, &BorderBrush, BarRect); + } + + pDC->SelectClipRgn(NULL); + DeleteObject(BorderBrush); + DeleteObject(FillBrush); +} + +void CChartGanttSerie::DrawAll(CDC *pDC) +{ + if (!m_bIsVisible) + return; + if (!pDC->GetSafeHdc()) + return; + + unsigned uFirst=0, uLast=0; + if (!GetVisiblePoints(uFirst,uLast)) + return; + + CRect TempClipRect(m_PlottingRect); + TempClipRect.DeflateRect(1,1); + if (uFirst>0) + uFirst--; + if (uLastSetBkMode(TRANSPARENT); + pDC->IntersectClipRect(TempClipRect); + + CBrush BorderBrush(m_BorderColor); + CBrush FillBrush(m_SerieColor); + for (m_uLastDrawnPoint=uFirst;m_uLastDrawnPoint<=uLast;m_uLastDrawnPoint++) + { + CRect BarRect = GetBarRectangle(m_uLastDrawnPoint); + DrawBar(pDC, &FillBrush, &BorderBrush, BarRect); + } + + pDC->SelectClipRgn(NULL); + DeleteObject(BorderBrush); + DeleteObject(FillBrush); +} + +void CChartGanttSerie::SetBorderColor(COLORREF BorderColor) +{ + m_BorderColor = BorderColor; + m_pParentCtrl->RefreshCtrl(); +} +void CChartGanttSerie::SetBorderWidth(int Width) +{ + m_iBorderWidth = Width; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartGanttSerie::SetBarWidth(int Width) +{ + m_iBarWidth = Width; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartGanttSerie::ShowGradient(bool bShow) +{ + m_bGradient = bShow; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartGanttSerie::SetGradient(COLORREF GradientColor, EGradientType GradientType) +{ + m_GradientColor = GradientColor; + m_GradientType = GradientType; + m_pParentCtrl->RefreshCtrl(); +} + +CRect CChartGanttSerie::GetBarRectangle(unsigned uPointIndex) const +{ + SChartGanttPoint point = GetPoint(uPointIndex); + int PointXStart = m_pHorizontalAxis->ValueToScreen(point.StartTime); + int PointXEnd = m_pHorizontalAxis->ValueToScreen(point.EndTime); + int YVal = m_pVerticalAxis->ValueToScreen(point.YValue); + int PointYStart = YVal - m_iBarWidth; + int PointYEnd = YVal + m_iBarWidth; + CRect PointRect(min(PointXStart, PointXEnd), min(PointYStart, PointYEnd), + max(PointXStart, PointXEnd), max(PointYStart, PointYEnd) ); + return PointRect; +} + +void CChartGanttSerie::DrawBar(CDC* pDC, CBrush* pFillBrush, CBrush* pBorderBrush, + CRect BarRect) +{ + if (m_bShadow) + { + CBrush ShadowBrush(m_ShadowColor); + CRect ShadowRect(BarRect); + ShadowRect.OffsetRect(m_iShadowDepth,m_iShadowDepth); + pDC->FillRect(ShadowRect,&ShadowBrush); + } + pDC->FillRect(BarRect,pBorderBrush); + + CRect FillRect(BarRect); + FillRect.DeflateRect(m_iBorderWidth,m_iBorderWidth); + if (m_bGradient) + { + CChartGradient::DrawGradient(pDC,FillRect,m_SerieColor,m_GradientColor, + m_GradientType); + } + else + { + pDC->FillRect(FillRect,pFillBrush); + } +} \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartGanttSerie.h b/ChartDemo/ChartCtrl/ChartGanttSerie.h new file mode 100644 index 0000000..ccbaaf2 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartGanttSerie.h @@ -0,0 +1,162 @@ +/* + * + * ChartGanttSerie.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#pragma once +#include "ChartSerieBase.h" + +//! Point structure used as template parameter for gantt series +struct SChartGanttPoint +{ + //! Default constructor + SChartGanttPoint() : StartTime(0.0), EndTime(0.0), YValue(0.0) { } + //! Construct a new gantt point with the specifed values + SChartGanttPoint(double Start, double End, double YVal) + : StartTime(Start), EndTime(End), YValue(YVal) { } + + //! The start time of the gantt point + double StartTime; + //! The end time of the gantt point + double EndTime; + //! The Y value of the gantt point + double YValue; + + //! Returns the X value of the point, which is the average between start time and end time + double GetX() const { return (EndTime-StartTime)/2; } + //! Returns the Y value + double GetY() const { return YValue; } + //! Returns the start time + double GetXMin() const { return StartTime; } + //! Returns the end time + double GetXMax() const { return EndTime; } + //! Returns the Y value + double GetYMin() const { return YValue; } + //! Returns the Y value + double GetYMax() const { return YValue; } +}; + +//! Specialization of a CChartSerieBase to display a gantt series. +/** + Each point in a gantt series is amde of three values: a start and + end time and an Y value. The points are displayed as horizontal bars + that are positionned on the Y axis depending on their Y value and + which starts at the start time and end at the end time along the X + axis. +**/ +class CChartGanttSerie : public CChartSerieBase +{ +public: + //! Constructor + CChartGanttSerie(CChartCtrl* pParent); + //! Destructor + ~CChartGanttSerie(); + + //! Adds a new point to the series. + /** + @param StartTime + The start time of the Gantt bar + @param EndTime + The end time of the Gantt bar + @param YValue + The YValue of the Gantt bar + **/ + void AddPoint(double StartTime, double EndTime, double YValue); + + //! Tests if a certain screen point is on the series. + /** + @param screenPoint + The screen point to test + @param uIndex + If the point is close to a specific point of the series, its index is stored here. + @return true if the point is on the series + **/ + bool IsPointOnSerie(const CPoint& screenPoint, unsigned& uIndex) const; + + //! Sets the bars border color + void SetBorderColor(COLORREF BorderColor); + //! Returns the bars border color + COLORREF GetBorderColor() const { return m_BorderColor; } + //! Sets the bars border width + void SetBorderWidth(int Width); + //! Returns the bars border width + int GetBorderWidth() const { return m_iBorderWidth; } + //! Sets the bars width (in pixels) + void SetBarWidth(int Width); + //! Returns the bars width (in pixels) + int GetBarWidth() const { return m_iBarWidth; } + + //! Specifies if a gradient is applied to the bars + void ShowGradient(bool bShow); + //! Sets the gradient style + /** + @param GradientColor + The second color used for the gradient (the first one being + the original series color). + @param GradientType + The type of gradient used between the two colors (vertical, horizontal, ...) + **/ + void SetGradient(COLORREF GradientColor, EGradientType GradientType); + +protected: + //! Draws the legend icon for the series. + /** + @param pDC + The device context used to draw + @param rectBitmap + The rectangle in which to draw the legend icon + **/ + void DrawLegend(CDC* pDC, const CRect& rectBitmap) const; + + //! Draws the most recent points of the series. + /** + This function should only draw the points that were not previously + drawn. + @param pDC + The device context used to draw + **/ + void Draw(CDC* pDC); + //! Redraws the full series. + /** + @param pDC + The device context used to draw + **/ + void DrawAll(CDC *pDC); + +private: + //! Returns the rectangle of a specific point of the series. + CRect GetBarRectangle(unsigned uPointIndex) const; + + void DrawBar(CDC* pDC, CBrush* pFillBrush, CBrush* pBorderBrush, + CRect BarRect); + + //! The bar width + int m_iBarWidth; + //! The bar border width + int m_iBorderWidth; + //! The bar border color + COLORREF m_BorderColor; + + //! True if a gradient is applied to fill the bar + bool m_bGradient; + //! The second color of the gradient + COLORREF m_GradientColor; + //! The type of gradient to apply + EGradientType m_GradientType; +}; diff --git a/ChartDemo/ChartCtrl/ChartGradient.cpp b/ChartDemo/ChartCtrl/ChartGradient.cpp new file mode 100644 index 0000000..40cf252 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartGradient.cpp @@ -0,0 +1,127 @@ +/* + * + * ChartGradient.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#include "stdafx.h" +#include "ChartGradient.h" + +CChartGradient::CChartGradient() +{ +} + +CChartGradient::~CChartGradient() +{ +} + +void CChartGradient::DrawGradient(CDC* pDC, const CRect& GradientRect, COLORREF Color1, + COLORREF Color2, EGradientType GradientType) +{ +#if _MFC_VER > 0x0600 + if ( (GradientType == gtHorizontal) || (GradientType == gtVertical) ) + { + TRIVERTEX vertex[2] ; + vertex[0].x = GradientRect.left; + vertex[0].y = GradientRect.top; + vertex[0].Red = ((COLOR16)GetRValue(Color1))<<8; + vertex[0].Green = ((COLOR16)GetGValue(Color1))<<8; + vertex[0].Blue = ((COLOR16)GetBValue(Color1))<<8; + vertex[0].Alpha = 0x0000; + vertex[1].x = GradientRect.right; + vertex[1].y = GradientRect.bottom; + vertex[1].Red = ((COLOR16)GetRValue(Color2))<<8; + vertex[1].Green = ((COLOR16)GetGValue(Color2))<<8; + vertex[1].Blue = ((COLOR16)GetBValue(Color2))<<8; + vertex[1].Alpha = 0x0000; + GRADIENT_RECT gRect; + gRect.UpperLeft = 0; + gRect.LowerRight = 1; + if (GradientType == gtHorizontal) + pDC->GradientFill(vertex,2,&gRect,1,GRADIENT_FILL_RECT_H); + else + pDC->GradientFill(vertex,2,&gRect,1,GRADIENT_FILL_RECT_V); + } + else + { + for (int i=0;i<2; i++) + { + TRIVERTEX vertex[2] ; + if (GradientType == gtHorizontalDouble) + { + vertex[0].x = GradientRect.left + (GradientRect.Width()/2) * i; + vertex[0].y = GradientRect.top; + } + else + { + vertex[0].x = GradientRect.left; + vertex[0].y = GradientRect.top + (GradientRect.Height()/2) * i; + } + if (i==0) + { + vertex[0].Red = ((COLOR16)GetRValue(Color1))<<8; + vertex[0].Green = ((COLOR16)GetGValue(Color1))<<8; + vertex[0].Blue = ((COLOR16)GetBValue(Color1))<<8; + } + else + { + vertex[0].Red = ((COLOR16)GetRValue(Color2))<<8; + vertex[0].Green = ((COLOR16)GetGValue(Color2))<<8; + vertex[0].Blue = ((COLOR16)GetBValue(Color2))<<8; + } + vertex[0].Alpha = 0x0000; + if (GradientType == gtHorizontalDouble) + { + vertex[1].x = GradientRect.left + (GradientRect.Width()/2) * (i+1); + vertex[1].y = GradientRect.bottom; + } + else + { + vertex[1].x = GradientRect.right; + vertex[1].y = GradientRect.top + (GradientRect.Height()/2) * (i+1); + } + if (i==0) + { + vertex[1].Red = ((COLOR16)GetRValue(Color2))<<8; + vertex[1].Green = ((COLOR16)GetGValue(Color2))<<8; + vertex[1].Blue = ((COLOR16)GetBValue(Color2))<<8; + } + else + { + vertex[1].Red = ((COLOR16)GetRValue(Color1))<<8; + vertex[1].Green = ((COLOR16)GetGValue(Color1))<<8; + vertex[1].Blue = ((COLOR16)GetBValue(Color1))<<8; + } + vertex[1].Alpha = 0x0000; + + GRADIENT_RECT gRect; + gRect.UpperLeft = 0; + gRect.LowerRight = 1; + if (GradientType == gtHorizontalDouble) + pDC->GradientFill(vertex,2,&gRect,1,GRADIENT_FILL_RECT_H); + else + pDC->GradientFill(vertex,2,&gRect,1,GRADIENT_FILL_RECT_V); + } + } +#else + CBrush NewBrush(Color1); + pDC->FillRect(GradientRect,&NewBrush); + DeleteObject(NewBrush); +#endif + +} diff --git a/ChartDemo/ChartCtrl/ChartGradient.h b/ChartDemo/ChartCtrl/ChartGradient.h new file mode 100644 index 0000000..00b16c1 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartGradient.h @@ -0,0 +1,65 @@ +/* + * + * ChartGradient.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#pragma once + +//! Types of gradients that can be used +enum EGradientType +{ + //! A simple horizontal gradient (from the first color to the second) + gtHorizontal, + //! A simple Vertical gradient (from the first color to the second) + gtVertical, + //! A double horizontal gradient (first color to second and back to first) + gtHorizontalDouble, + //! A double vertical gradient (first color to second and back to first) + gtVerticalDouble +}; + +//! Helper class to draw gradient. +/** + It only contains a static function to draw the gradient. This is + mainly used internally. +**/ +class CChartGradient +{ +public: + //! Constructor + CChartGradient(); + //! Destructor + ~CChartGradient(); + + //! Draws a gradient between two colors inside a rectangle. + /** + @param pDC + The device context with which to draw. + @param GradientRect + The rectangle in which to draw the gradient + @param Color1 + The first gradient color + @param Color2 + The second gradient color + @param GradientType + The type of gradient to use in the rectangle + **/ + static void DrawGradient(CDC* pDC, const CRect& GradientRect, COLORREF Color1, + COLORREF Color2, EGradientType GradientType); +}; diff --git a/ChartDemo/ChartCtrl/ChartGrid.cpp b/ChartDemo/ChartCtrl/ChartGrid.cpp new file mode 100644 index 0000000..400ce76 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartGrid.cpp @@ -0,0 +1,123 @@ +/* + * + * ChartGrid.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#include "stdafx.h" +#include "ChartGrid.h" +#include "ChartAxis.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +using namespace std; + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CChartGrid::CChartGrid() + : m_GridColor(RGB(128,128,128)), m_pParentCtrl(NULL), m_bIsVisible(true), + m_bIsHorizontal(true), m_lstTickPos() +{ +} + +CChartGrid::~CChartGrid() +{ + +} + +void CChartGrid::AddTick(int Position) +{ + m_lstTickPos.push_back(Position); +} + +void CChartGrid::ClearTicks() +{ + m_lstTickPos.clear(); +} + +void CChartGrid::Draw(CDC *pDC) +{ + if (!m_bIsVisible) + return; + if (!pDC->GetSafeHdc() ) + return; + + CRect plottingRect = m_pParentCtrl->GetPlottingRect(); + pDC->IntersectClipRect(plottingRect); + + CPen* pOldPen; + CPen NewPen(PS_SOLID,0,m_GridColor); + pOldPen = pDC->SelectObject(&NewPen); + + list::iterator iter = m_lstTickPos.begin(); + int ActuPosition = 0; + + for (iter; iter!=m_lstTickPos.end(); iter++) + { + ActuPosition = *iter; + if (!m_bIsHorizontal) + { + int ActuX = plottingRect.left; + + while (ActuXMoveTo(ActuX,ActuPosition); + ActuX += 3; + pDC->LineTo(ActuX,ActuPosition); + ActuX += 3; + } + } + else + { + int ActuY = plottingRect.bottom; + + while (ActuY>plottingRect.top) + { + pDC->MoveTo(ActuPosition,ActuY); + ActuY -= 3; + pDC->LineTo(ActuPosition,ActuY); + ActuY -= 3; + } + } + } + + pDC->SelectClipRgn(NULL); + pDC->SelectObject(pOldPen); + NewPen.DeleteObject(); +} + +void CChartGrid::SetVisible(bool bVisible) +{ + m_bIsVisible = bVisible; + if (m_pParentCtrl) + m_pParentCtrl->RefreshCtrl(); +} + +void CChartGrid::SetColor(COLORREF NewColor) +{ + m_GridColor = NewColor; + if (m_pParentCtrl) + m_pParentCtrl->RefreshCtrl(); +} diff --git a/ChartDemo/ChartCtrl/ChartGrid.h b/ChartDemo/ChartCtrl/ChartGrid.h new file mode 100644 index 0000000..b5e7c01 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartGrid.h @@ -0,0 +1,83 @@ +/* + * + * ChartGrid.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#if !defined(AFX_CHARTGRID_H__ECCBEFF4_2365_49CD_A865_F1B4DD8CA138__INCLUDED_) +#define AFX_CHARTGRID_H__ECCBEFF4_2365_49CD_A865_F1B4DD8CA138__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include +#include "ChartCtrl.h" + + +class CChartAxis; + +//! Class which draws the grid associated with a specific axis. +/** + This object is retrieved through the CChartAxis::GetGrid function. +**/ +class CChartGrid +{ + friend CChartAxis; + +public: + //! Shows/hides the grid. + void SetVisible(bool bVisible); + //! Returns true if the grid is visible. + bool IsVisible() const { return m_bIsVisible; } + + //! Sets the color of the grid. + void SetColor(COLORREF NewColor); + //! Returns the grid color. + COLORREF GetColor() const { return m_GridColor; } + +private: + //! Constructor + CChartGrid(); + //! Destructor + virtual ~CChartGrid(); + + //! Draws the grid + void Draw(CDC* pDC); + + //! Add a tick at a certain position + void AddTick(int Position); + //! Removes all the ticks. + void ClearTicks(); + + + //! The grid color. + COLORREF m_GridColor; + + //! The parent charting control. + CChartCtrl* m_pParentCtrl; + //! Specifies if the grid is visible or not. + bool m_bIsVisible; + + //! List containing all the tick positions. + std::list m_lstTickPos; + //! Specifies if the grid is associated with a vertical or horizontal axis. + bool m_bIsHorizontal; +}; + +#endif // !defined(AFX_CHARTGRID_H__ECCBEFF4_2365_49CD_A865_F1B4DD8CA138__INCLUDED_) diff --git a/ChartDemo/ChartCtrl/ChartLabel.h b/ChartDemo/ChartCtrl/ChartLabel.h new file mode 100644 index 0000000..d9fb23a --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartLabel.h @@ -0,0 +1,122 @@ +/* + * + * ChartLabel.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#ifndef _CHARTLABEL_H_ +#define _CHARTLABEL_H_ + +template +class CChartSerieBase; + +//! Interface which should be implemented in order to provide text to a label. +/** + This class is a template class with the template parameter being the point + type of the series to which the label is attached. + + Using a CChartLabelProvider provides more flexibility in the way to + supply text to the label. You can for instance embedd in the string some + information about the point (XValue, YValue, index, ...). In that case, a + single CChartLabelProvider object can be provided for all labels. Changing + the displayed text of all labels becomes also easier: you only have to adapt + the string returned by this object and refresh the control and all labels will + be updated. +**/ +template +class CChartLabelProvider +{ +public: + //! Constructor + CChartLabelProvider() { } + //! Destructor + virtual ~CChartLabelProvider() { } + + //! Method to override in order to provide the text of the label. + /** + @param pSerie + The series to which the label is attached + @param uPtIndex + The index of the point in the series to which the label is attached + @return a string which will be the text displayed in the label. + **/ + virtual TChartString GetText(CChartSerieBase* pSerie, + unsigned PointIndex) = 0; +}; + +//! Draws a label containing some text which is attached to a point of a series. +/** + This is a base class which should be overriden for specific label types. +**/ +template +class CChartLabel +{ + friend CChartSerieBase; + +public: + //! Sets a static text to be displayed in the label. + void SetLabelText(const TChartString& strText); + //! Sets the font of the text label. + /** + @param nPointSize + The font point size + @param strFaceName + The font face name + **/ + void SetFont(int nPointSize, const TChartString& strFaceName); + //! Shows/hides the label. + void SetVisisble(bool bVisible); + //! Sets a label provider for more flexibility in how the text is supplied. + void SetLabelProvider(CChartLabelProvider* pProvider) + { + m_pLabelProvider = pProvider; + } + +protected: + //! Constructor + CChartLabel(CChartCtrl* pParentCtrl, CChartSerieBase* pParentSeries); + //! Destructor + virtual ~CChartLabel(); + + //! Draws the label. + /** + This pure virtual function must be overriden by all child classes. + **/ + virtual void Draw(CDC* pDC, unsigned uPointIndex) = 0; + + //! Specifies if the label is visible or not. + bool m_bIsVisible; + //! The text font size. + int m_iFontSize; + //! The text font face name. + TChartString m_strFontName; + + //! The static text of the label. + TChartString m_strLabelText; + //! The text provider. + CChartLabelProvider* m_pLabelProvider; + + //! The parent charting control. + CChartCtrl* m_pParentCtrl; + //! The parent series. + CChartSerieBase* m_pParentSeries; +}; + +#include "ChartLabel.inl" + +#endif // _CHARTLABEL_H_ \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartLabel.inl b/ChartDemo/ChartCtrl/ChartLabel.inl new file mode 100644 index 0000000..9b887ed --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartLabel.inl @@ -0,0 +1,59 @@ +/* + * + * ChartLabel.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#include "ChartCtrl.h" + +template +CChartLabel::CChartLabel(CChartCtrl* pParentCtrl, + CChartSerieBase* pParentSeries) + : m_iFontSize(100),m_strFontName(_T("Microsoft Sans Serif")), + m_strLabelText(_T("")), m_pLabelProvider(NULL), m_pParentCtrl(pParentCtrl), + m_pParentSeries(pParentSeries) +{ +} + +template +CChartLabel::~CChartLabel() +{ +} + +template +void CChartLabel::SetLabelText(const TChartString& strText) +{ + m_strLabelText = strText; + m_pParentCtrl->RefreshCtrl(); +} + +template +void CChartLabel::SetFont(int nPointSize, const TChartString& strFaceName) +{ + m_iFontSize = nPointSize; + m_strFontName = strFaceName; + m_pParentCtrl->RefreshCtrl(); +} + +template +void CChartLabel::SetVisisble(bool bVisible) +{ + m_bIsVisible = bVisible; + m_pParentCtrl->RefreshCtrl(); +} + diff --git a/ChartDemo/ChartCtrl/ChartLegend.cpp b/ChartDemo/ChartCtrl/ChartLegend.cpp new file mode 100644 index 0000000..bfbcb11 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartLegend.cpp @@ -0,0 +1,357 @@ +/* + * + * ChartLegend.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * History: + * - 02/03/2008: Legend can now be docked on any side or can be floating. + * - 02/03/2008: Added support for transparent legend. + * - 24/03/2008: Bug fix for invisible series. + * - 28/03/2008: Support for horizontal legend. + * - 28/03/2008: Bitmap size is now the same for all series. + * + */ + +#include "stdafx.h" +#include "ChartLegend.h" +#include "ChartSerie.h" +#include "ChartCtrl.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CChartLegend::CChartLegend(CChartCtrl* pParent) +{ + m_pParentCtrl = pParent; + m_BackColor = RGB(255,255,255); + m_iFontSize = 100; + m_strFontName = _T("Times New Roman"); + + m_bIsVisible = false; + + m_bDocked = true; + m_DockSide = dsDockRight; + m_iLeftPos = m_iTopPos = 0; + m_bIsTransparent = false; + m_bIsHorizontal = false; + + m_bShadow = true; + m_iShadowDepth = 3; + m_BitmapSize.cx = 16; + m_BitmapSize.cy = 16; +} + +CChartLegend::~CChartLegend() +{ +} + +void CChartLegend::SetVisible(bool bVisible) +{ + m_bIsVisible = bVisible; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartLegend::SetBackColor(COLORREF NewColor) +{ + m_BackColor = NewColor; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartLegend::SetShadowColor(COLORREF NewColor) +{ + m_ShadowColor = NewColor; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartLegend::EnableShadow(bool bEnable) +{ + m_bShadow = bEnable; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartLegend::SetShadowDepth(int Depth) +{ + m_iShadowDepth = Depth; + m_pParentCtrl->RefreshCtrl(); +} + +BOOL CChartLegend::IsPointInside(const CPoint& screenPoint) const +{ + return m_LegendRect.PtInRect(screenPoint); +} + +void CChartLegend::SetFont(int iPointSize, const TChartString& strFaceName) +{ + m_iFontSize = iPointSize; + m_strFontName = strFaceName; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartLegend::SetTransparent(bool bTransparent) +{ + m_bIsTransparent = bTransparent; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartLegend::SetHorizontalMode(bool bHorizontal) +{ + m_bIsHorizontal = bHorizontal; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartLegend::DockLegend(DockSide dsSide) +{ + m_bDocked = true; + m_DockSide = dsSide; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartLegend::UndockLegend(int iLeftPos, int iTopPos) +{ + m_bDocked = false; + m_iLeftPos = iLeftPos; + m_iTopPos = iTopPos; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartLegend::ClipArea(CRect& rcControl, CDC* pDC) +{ + UpdatePosition(pDC,rcControl); + if (m_LegendRect.IsRectEmpty()) + return; + + if (m_bDocked) + { + switch (m_DockSide) + { + case dsDockRight: + rcControl.right = m_LegendRect.left + 2; + break; + case dsDockLeft: + rcControl.left = m_LegendRect.right - 2; + break; + case dsDockTop: + rcControl.top = m_LegendRect.bottom + 2; + break; + case dsDockBottom: + rcControl.bottom = m_LegendRect.top - 2; + break; + } + } +} + +void CChartLegend::UpdatePosition(CDC* pDC, const CRect& rcControl) +{ + CRect NewPosition; + NewPosition.SetRectEmpty(); + if (!m_bIsVisible) + { + m_LegendRect = NewPosition; + return; + } + + CFont* pOldFont; + CFont NewFont; + NewFont.CreatePointFont(m_iFontSize,m_strFontName.c_str(),pDC); + pOldFont = pDC->SelectObject(&NewFont); + + int Height = 0; + int Width = 0; + int MaxText = 0; + CSize TextSize; + + m_pParentCtrl->GoToFirstSerie(); + int Drawn = 0; + while (CChartSerie* pSerie=m_pParentCtrl->GetNextSerie()) + { + if ( (pSerie->GetName() == _T("")) || !pSerie->IsVisible() ) + continue; + + Drawn++; + TextSize = pDC->GetTextExtent(pSerie->GetName().c_str()); + + if (!m_bIsHorizontal) + { + if (TextSize.cy>m_BitmapSize.cy) + Height += TextSize.cy + 2; + else + Height += m_BitmapSize.cy + 2; + + if (TextSize.cx > MaxText) + MaxText = TextSize.cx; + } + else + { + Width += TextSize.cx + 4 + m_BitmapSize.cx + 10; + if (TextSize.cy > MaxText) + MaxText = TextSize.cy; + } + } + pDC->SelectObject(pOldFont); + DeleteObject(NewFont); + + if (!Drawn) + { + m_LegendRect = NewPosition; + return; + } + + if (!m_bIsHorizontal) + { + Width += MaxText + m_BitmapSize.cx + 12; + Height += 4 + 4 - 2; // Top and bottom margins. -2 because space counted once too much + } + else + { + Width += 2 + 2 - 10; + Height = 4 + max(m_BitmapSize.cy,MaxText) + 4; + } + + if (!m_bDocked) + { + NewPosition.top = m_iTopPos; + NewPosition.left = m_iLeftPos; + NewPosition.bottom = m_iTopPos + Height + 2; + NewPosition.right = m_iLeftPos + Width; + } + else + { + switch (m_DockSide) + { + case dsDockRight: + NewPosition.top = ((rcControl.bottom-rcControl.top)/2) - ((Height + 2)/2); + NewPosition.left = rcControl.right - (Width + 6); + NewPosition.bottom = NewPosition.top + Height; + NewPosition.right = NewPosition.left + Width; + break; + case dsDockLeft: + NewPosition.top = ((rcControl.bottom-rcControl.top)/2) - ((Height + 2)/2); + NewPosition.left = rcControl.left + 3; + NewPosition.bottom = NewPosition.top + Height; + NewPosition.right = NewPosition.left + Width; + break; + case dsDockTop: + NewPosition.top = rcControl.top + 3; //((rcControl.bottom-rcControl.top)/2) - ((Height + 2)/2); + NewPosition.left = ((rcControl.right-rcControl.left)/2) - (Width/2); // rcControl.left + 3; + NewPosition.bottom = NewPosition.top + Height; + NewPosition.right = NewPosition.left + Width; + break; + case dsDockBottom: + NewPosition.top = rcControl.bottom - (Height + 2); //((rcControl.bottom-rcControl.top)/2) - ((Height + 2)/2); + NewPosition.left = ((rcControl.right-rcControl.left)/2) - (Width/2); // rcControl.left + 3; + NewPosition.bottom = NewPosition.top + Height; + NewPosition.right = NewPosition.left + Width; + break; + } + } + m_LegendRect = NewPosition; +} + +void CChartLegend::Draw(CDC *pDC) +{ + if (!pDC->GetSafeHdc()) + return; + if (!m_bIsVisible) + return; + if (m_LegendRect.IsRectEmpty()) + return; + + CPen SolidPen(PS_SOLID,0,RGB(0,0,0)); + CPen* pOldPen; + CFont* pOldFont; + CFont NewFont; + NewFont.CreatePointFont(m_iFontSize,m_strFontName.c_str(),pDC); + + // Draw the shadow + if (m_bShadow) + { + CRect ShadowRect = m_LegendRect; + ShadowRect.OffsetRect(m_iShadowDepth,m_iShadowDepth); + CBrush BrushShadow; + BrushShadow.CreateSolidBrush(m_ShadowColor) ; + pDC->FillRect(ShadowRect,&BrushShadow); + } + + if (!m_bIsTransparent) + { + //Fill back color + CBrush BrushBack; + BrushBack.CreateSolidBrush(m_BackColor) ; + pDC->FillRect(m_LegendRect,&BrushBack); + } + + pOldFont = pDC->SelectObject(&NewFont); + pOldPen = pDC->SelectObject(&SolidPen); + + //Draw rectangle: + pDC->MoveTo(m_LegendRect.left,m_LegendRect.top); + pDC->LineTo(m_LegendRect.right,m_LegendRect.top); + pDC->LineTo(m_LegendRect.right,m_LegendRect.bottom); + pDC->LineTo(m_LegendRect.left,m_LegendRect.bottom); + pDC->LineTo(m_LegendRect.left,m_LegendRect.top); + + int iPrevMode = pDC->SetBkMode(TRANSPARENT); + CRect rectBitmap(m_LegendRect.left+2,m_LegendRect.top+5, + m_LegendRect.left+2+m_BitmapSize.cx, + m_LegendRect.top+6+m_BitmapSize.cy); + m_pParentCtrl->GoToFirstSerie(); + while (CChartSerie* pSerie=m_pParentCtrl->GetNextSerie()) + { + if ( (pSerie->GetName() == _T("")) || !pSerie->IsVisible() ) + continue; + + int MaxHeight = 0; + CSize TextSize = pDC->GetTextExtent(pSerie->GetName().c_str()); + if (TextSize.cy > m_BitmapSize.cy) + { + pDC->ExtTextOut(rectBitmap.right+4,rectBitmap.top,ETO_CLIPPED,NULL,pSerie->GetName().c_str(),NULL); + CRect rectTemp(rectBitmap); + int YOffset = TextSize.cy/2 - rectBitmap.Height()/2; + rectTemp.OffsetRect(0,YOffset); + pSerie->DrawLegend(pDC,rectTemp); + MaxHeight = TextSize.cy; + } + else + { + int YOffset = rectBitmap.CenterPoint().y - TextSize.cy/2; + pDC->ExtTextOut(rectBitmap.right+4,YOffset,ETO_CLIPPED,NULL,pSerie->GetName().c_str(),NULL); + MaxHeight = m_BitmapSize.cy; + pSerie->DrawLegend(pDC,rectBitmap); + } + + + if (!m_bIsHorizontal) + rectBitmap.OffsetRect(0,MaxHeight+2); + else + rectBitmap.OffsetRect(m_BitmapSize.cx+4+TextSize.cx+10,0); + } + + pDC->SetBkMode(iPrevMode); + pDC->SelectObject(pOldFont); + DeleteObject(NewFont); + pDC->SelectObject(pOldPen); + DeleteObject(SolidPen); +} + + + diff --git a/ChartDemo/ChartCtrl/ChartLegend.h b/ChartDemo/ChartCtrl/ChartLegend.h new file mode 100644 index 0000000..6b24d4d --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartLegend.h @@ -0,0 +1,155 @@ +/* + * + * ChartLegend.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#if !defined(AFX_CHARTLEGEND_H__CD72E5A0_8F52_472A_A611_C588F642080B__INCLUDED_) +#define AFX_CHARTLEGEND_H__CD72E5A0_8F52_472A_A611_C588F642080B__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "ChartCtrl.h" + +#include "ChartString.h" + +class CChartSerie; + +//! This class is responsible for the legend displayed on the control. +/** + Series which are named will be displayed in the legend. The legend + object is retrieved by calling the GetLegend() function on the + CChartCtrl class. +**/ +class CChartLegend +{ + friend CChartCtrl; + +public: + //! Sets the font used to display the series names. + void SetFont(int iPointSize, const TChartString& strFaceName); + + //! Enumeration specifying on which side of the control the legend is docked. + enum DockSide + { + dsDockRight, + dsDockLeft, + dsDockTop, + dsDockBottom + }; + + //! Dock the legend on a specific side of the control. Default is right. + void DockLegend(DockSide dsSide); + //! Undock the legend. + /** + When the legend is undocked (floating), it doesn't take any margin size + but is drawn on top of the control at the specified location (it can be + above the plotting area for instance). + @param iLeftPos + The left position of the legend, in pixels (from the left of the control) + @param iTopPos + The top position of the legend, in pixels (from the top of the control) + **/ + void UndockLegend(int iLeftPos, int iTopPos); + + //! Sets the background of the legend transparent. + void SetTransparent(bool bTransparent); + //! Sets the legend in horizontal/vertical mode. + /** + In horizontal mode, the names are drawn next to each other + instead of on top of each other. + **/ + void SetHorizontalMode(bool bHorizontal); + + //! Sets the legend visible/invisible. + void SetVisible(bool bVisible); + //! Returns true if the legend is visible. + bool IsVisible() const { return m_bIsVisible; } + + //! Returns the back color of the legend. + COLORREF GetBackColor() const { return m_BackColor; } + //! Sets the back color of the legend. + void SetBackColor(COLORREF NewColor); + //! Returns the shadow color. + COLORREF GetShadowColor() const { return m_ShadowColor; } + //! Sets the shadow color. + void SetShadowColor(COLORREF NewColor); + //! Enables/disables the shadow. + void EnableShadow(bool bEnable); + //! Sets the shadow depth (in pixels). + void SetShadowDepth(int Depth); + + //! Returns true if the screen point is on the legend region. + BOOL IsPointInside(const CPoint& screenPoint) const; + +private: + //! Constructor + CChartLegend(CChartCtrl* pParent); + //! Destructor + virtual ~CChartLegend(); + + //! Draw the legend. + void Draw(CDC* pDC); + //! Remove the area needed for the legend from the chart rectangle. + void ClipArea(CRect& rcControl, CDC* pDC); + //! Recalculate the legend size and position. + void UpdatePosition(CDC* pDC, const CRect& rcControl); + + //! The parent charting control. + CChartCtrl* m_pParentCtrl; + //! The rectangle used to draw the legend. + CRect m_LegendRect; + + //! The font face name used to display the series names. + TChartString m_strFontName; + //! The font point size. + int m_iFontSize; + + //! True if the legend is docked + bool m_bDocked; + //! The side of the control on which the legend is docked. + DockSide m_DockSide; + + //! The left position of the legend if in floating mode. + int m_iLeftPos; + //! The top position of the legend if in floating mode. + int m_iTopPos; + + //! Specifies if the legend is visible. + bool m_bIsVisible; + //! Specifies if the background of the legend is transparent. + bool m_bIsTransparent; + //! Specifies if the legend is in horizontal mode. + bool m_bIsHorizontal; + //! Specifies if the legend shadow should be displayed. + bool m_bShadow; + //! Specifies the shadow depth (in pixels). + int m_iShadowDepth; + + //! Specifies the legend back color. + COLORREF m_BackColor; + //! Specifies the shadow color. + COLORREF m_ShadowColor; + + //! Specifies the size of the bitmap used by each series. + CSize m_BitmapSize; +}; + +#endif // !defined(AFX_CHARTLEGEND_H__CD72E5A0_8F52_472A_A611_C588F642080B__INCLUDED_) diff --git a/ChartDemo/ChartCtrl/ChartLineSerie.cpp b/ChartDemo/ChartCtrl/ChartLineSerie.cpp new file mode 100644 index 0000000..e3c87fe --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartLineSerie.cpp @@ -0,0 +1,360 @@ +/* + * + * ChartLineSerie.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * History: + * - 25/03/2008: Line series with a width > 1 can now have a style other than solid + * (thanks to Bruno Lavier). + * - 12/08/2008: Performance fix: pen use the PS_GEOMETRIC style only when necessary + * (thanks to Nick Holgate). + * + * + */ + +#include "stdafx.h" +#include "ChartLineSerie.h" +#include "ChartCtrl.h" + +#include "Math.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CChartLineSerie::CChartLineSerie(CChartCtrl* pParent) : CChartXYSerie(pParent) +{ + m_iLineWidth = 1; + m_iPenStyle = PS_SOLID; + m_bSmooth = false; + m_bShadow = false; +} + +CChartLineSerie::~CChartLineSerie() +{ + +} + +void CChartLineSerie::SetPenStyle(int NewStyle) +{ + m_iPenStyle = NewStyle; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartLineSerie::SetWidth(int PenWidth) +{ + m_iLineWidth = PenWidth; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartLineSerie::SetSmooth(bool bSmooth) +{ + m_bSmooth = bSmooth; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartLineSerie::DrawAll(CDC *pDC) +{ + if (!m_bIsVisible) + return; + if (!pDC->GetSafeHdc()) + return; + + unsigned uFirst=0, uLast=0; + if (!GetVisiblePoints(uFirst,uLast)) + return; + + if (uFirst>0) + uFirst--; + if (uLastSetBkMode(TRANSPARENT); + //To have lines limited in the drawing rectangle : + pDC->IntersectClipRect(m_PlottingRect); + pOldPen = pDC->SelectObject(&NewPen); + + if (m_bSmooth) + { + // For a Bezier curve, all points must be drawn. + uFirst = 0; + uLast = GetPointsCount() - 1; + SChartXYPoint* pKnots = NULL; + SChartXYPoint* pFirstControlPts = NULL; + SChartXYPoint* pSecondControlPts = NULL; + GetBezierControlPoints(uFirst,uLast,pKnots,pFirstControlPts,pSecondControlPts); + + unsigned Count = uLast - uFirst; + CPoint* pBezierPts = new CPoint[3*(Count-1)+1]; + CPoint* pShadowPts = NULL; + if (m_bShadow) + pShadowPts = new CPoint[3*(Count-1)+1]; + + unsigned index = 0; + for (unsigned n=0; nSelectObject(&ShadowPen); + pDC->PolyBezier(pShadowPts,3*(Count-1)+1); + pDC->SelectObject(&NewPen); + delete[] pShadowPts; + } + pDC->PolyBezier(pBezierPts,3*(Count-1)+1); + + delete[] pKnots; + delete[] pFirstControlPts; + delete[] pSecondControlPts; + delete[] pBezierPts; + } + else // Non-smoothed curve + { + if (uLast-uFirst >= 1) + { + CPoint* pPoints = new CPoint[uLast-uFirst+1]; + CPoint* pShadow = NULL; + if (m_bShadow) + pShadow = new CPoint[uLast-uFirst+1]; + + unsigned long pointsCount = 0; + CPoint LastScreenPoint; + for (m_uLastDrawnPoint=uFirst;m_uLastDrawnPoint<=uLast;m_uLastDrawnPoint++) + { + //We don't draw a line between the origin and the first point -> we must have + // a least 2 points before begining drawing + SChartXYPoint Point = GetPoint(m_uLastDrawnPoint); + CPoint ScreenPoint; + ValueToScreen(Point.X, Point.Y, ScreenPoint); + + if(LastScreenPoint != ScreenPoint) + { + //Only collate the unique points + pPoints[pointsCount] = ScreenPoint; + LastScreenPoint = ScreenPoint; + + if (m_bShadow) + { + ScreenPoint.Offset(m_iShadowDepth,m_iShadowDepth); + pShadow[pointsCount] = ScreenPoint; + } + pointsCount++; + } + } + + // We have to do that in order for the Draw function to work properly. + m_uLastDrawnPoint--; + if (m_bShadow) + { + pDC->SelectObject(&ShadowPen); + pDC->Polyline(pShadow, pointsCount); + } + pDC->SelectObject(&NewPen); + pDC->Polyline(pPoints, pointsCount); + + delete[] pPoints; + delete[] pShadow; + } + } + + pDC->SelectClipRgn(NULL); + pDC->SelectObject(pOldPen); + NewPen.DeleteObject(); + ShadowPen.DeleteObject(); +} + +void CChartLineSerie::Draw(CDC* pDC) +{ + if (!m_bIsVisible) + return; + + // If shadow or smooth is enabled, then the complete series + // must be redrawn. + if (m_bShadow || m_bSmooth) + { + DrawAll(pDC); + return; + } + + if (pDC->GetSafeHdc()) + { + CPen NewPen; + if (m_iPenStyle != PS_SOLID) + { + LOGBRUSH lb; + lb.lbStyle = BS_SOLID; + lb.lbColor = m_SerieColor; + NewPen.CreatePen(PS_GEOMETRIC | m_iPenStyle, m_iLineWidth, &lb); + } + else + { + NewPen.CreatePen(m_iPenStyle, m_iLineWidth, m_SerieColor); + } + CPen* pOldPen; + + pDC->SetBkMode(TRANSPARENT); + //To have lines limited in the drawing rectangle : + pDC->IntersectClipRect(m_pParentCtrl->GetPlottingRect()); + pOldPen = pDC->SelectObject(&NewPen); + + //Draw all points that haven't been drawn yet + for (m_uLastDrawnPoint;m_uLastDrawnPointMoveTo(ScreenPoint.x,ScreenPoint.y); + + Point = GetPoint(m_uLastDrawnPoint+1); + ValueToScreen(Point.X, Point.Y, ScreenPoint); + pDC->LineTo(ScreenPoint.x,ScreenPoint.y); + } + + pDC->SelectClipRgn(NULL); + pDC->SelectObject(pOldPen); + DeleteObject(NewPen); + } +} + +void CChartLineSerie::DrawLegend(CDC *pDC, const CRect& rectBitmap) const +{ + if (m_strSerieName== _T("")) + return; + + //Draw line: + LOGBRUSH lb; + lb.lbStyle = BS_SOLID; + lb.lbColor = m_SerieColor; + CPen NewPen(PS_GEOMETRIC | m_iPenStyle,m_iLineWidth,&lb); + CPen* pOldPen = pDC->SelectObject(&NewPen); + pDC->MoveTo(rectBitmap.left,rectBitmap.CenterPoint().y); + pDC->LineTo(rectBitmap.right,rectBitmap.CenterPoint().y); + pDC->SelectObject(pOldPen); + DeleteObject(NewPen); +} + +bool CChartLineSerie::IsPointOnSerie(const CPoint& screenPoint, unsigned& uIndex) const +{ + uIndex = INVALID_POINT; + if (!m_bIsVisible) + return false; + + unsigned uFirst=0, uLast=0; + if (!GetVisiblePoints(uFirst, uLast)) + return false; + if (uFirst>0) + uFirst--; + if (uLast 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "ChartXYSerie.h" + +//! Specialization of a CChartSerie to display a line series. +/** + The data points are connected by line segments. The curve can also + be smoothed. +**/ +class CChartLineSerie : public CChartXYSerie +{ +public: + //! Returns the pen style (plain, dashed, dotted, ...) + /** + For a list of pen styles available, see the CreatePen function in MSDN. + **/ + int GetPenStyle() const { return m_iPenStyle; } + //! Sets the pen style (plain, dashed, dotted, ...) + /** + For a list of pen styles available, see the CreatePen function in MSDN. + **/ + void SetPenStyle(int NewStyle); + + //! Returns the pen width + int GetWidth() const { return m_iLineWidth; } + //! Sets the pen width + void SetWidth(int PenWidth); + //! Enables the smoothing of the curve (slower). + void SetSmooth(bool bSmooth); + + //! Constructor + CChartLineSerie(CChartCtrl* pParent); + //! Destructor + virtual ~CChartLineSerie(); + + //! Check whether a screen point is on the series. + /** + This function returns true if the screen point is close to a line segment. + If the screen point is also close to a specific point of the series, the + index of the point is stored in the uIndex parameter. Otherwise, this + parameter contains INVALID_POINT. + @param screenPoint + The screen point to test + @param uIndex + If the point is close to a specific point of the series, its index is stored here. + @return true if the point is on the series + **/ + bool IsPointOnSerie(const CPoint& screenPoint, unsigned& uIndex) const; + +private: + //! Draws the legend icon for the series. + /** + @param pDC + The device context used to draw + @param rectBitmap + The rectangle in which to draw the legend icon + **/ + void DrawLegend(CDC* pDC, const CRect& rectBitmap) const; + + //! Draws the most recent points of the series. + /** + This function should only draw the points that were not previously + drawn. + @param pDC + The device context used to draw + **/ + void Draw(CDC* pDC); + //! Redraws the full series. + /** + @param pDC + The device context used to draw + **/ + void DrawAll(CDC *pDC); + + //! Checks whether a point is close to a line segment + bool IsNearLine(long Axl, long Ayl,long Bxl, + long Byl, long Cxl, long Cyl) const; + + + //! The pen width + int m_iLineWidth; + //! The pen style + int m_iPenStyle; + //! Specifies if the curve is smoothed + bool m_bSmooth; +}; + +#endif // !defined(AFX_CHARTLINESERIE_H__792C2F20_9650_42FA_B13D_E63911C98CE5__INCLUDED_) diff --git a/ChartDemo/ChartCtrl/ChartLogarithmicAxis.cpp b/ChartDemo/ChartCtrl/ChartLogarithmicAxis.cpp new file mode 100644 index 0000000..05a1b8d --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartLogarithmicAxis.cpp @@ -0,0 +1,190 @@ +/* + * + * ChartLogarithmicAxis.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + */ + +#include "stdafx.h" +#include "ChartLogarithmicAxis.h" +#include "ChartCtrl.h" +#include +#include +#include +#include + +using namespace std; + +CChartLogarithmicAxis::CChartLogarithmicAxis() + : CChartAxis(), m_dFirstTickValue(1) +{ +} + +CChartLogarithmicAxis::~CChartLogarithmicAxis() +{ +} + +double CChartLogarithmicAxis::GetFirstTickValue() const +{ + double dRetVal = m_dFirstTickValue; + if (m_bDiscrete) + dRetVal = m_dFirstTickValue/10; + return dRetVal; +} + +bool CChartLogarithmicAxis::GetNextTickValue(double dCurrentTick, + double& dNextTick) const +{ + dNextTick = dCurrentTick * 10; + if (dNextTick <= m_MaxValue) + return true; + else + return false; +} + +TChartString CChartLogarithmicAxis::GetTickLabel(double TickValue) const +{ + double fLogDecCount; + int nLogDecCount; + + fLogDecCount = log10(TickValue); + + if (fLogDecCount < 0.0) + nLogDecCount = (int)(fabs(fLogDecCount) + 0.1); + else + nLogDecCount = 0; + + TChartStringStream ssLabel; + ssLabel << fixed << setprecision(nLogDecCount) << TickValue; + return ssLabel.str(); +} + +long CChartLogarithmicAxis::ValueToScreenStandard(double Value) const +{ + long Offset = 0; + long retVal = 0; + + Offset = (int)floor((log10(Value)-log10(m_MinValue)) * GetAxisLenght()/(log10(m_MaxValue)-log10(m_MinValue)) ); + if (m_bIsHorizontal) + { + if (!m_bIsInverted) + retVal = (m_StartPos + Offset); + else + retVal = (m_EndPos - Offset); + } + else + { + if (!m_bIsInverted) + retVal = (m_StartPos - Offset); + else + retVal = (m_EndPos + Offset); + } + return retVal; +} + +long CChartLogarithmicAxis::ValueToScreenDiscrete(double Value) const +{ + // In discrete mode, al values between two ticks are "directed" + // to the middle of the interval. + double lowTick = pow(10,floor(log10(Value))); + double highTick = pow(10,floor(log10(Value*10))); + + long lowTickPos = ValueToScreenStandard(lowTick); + long highTickPos = ValueToScreenStandard(highTick); + return (lowTickPos + (highTickPos-lowTickPos)/2); +} + +double CChartLogarithmicAxis::ScreenToValue(long ScreenVal) const +{ + if (m_MaxValue==m_MinValue) + return m_MinValue; + + int AxisOffset = 0; + if (!m_bIsHorizontal) + { + if (m_bIsInverted) + AxisOffset = ScreenVal - m_EndPos; + else + AxisOffset = m_StartPos - ScreenVal; + } + else + { + if (!m_bIsInverted) + AxisOffset = ScreenVal - m_StartPos; + else + AxisOffset = m_EndPos - ScreenVal; + } + + return (pow(10.0,(AxisOffset *1.0 / GetAxisLenght()*(log10(m_MaxValue)-log10(m_MinValue)) ) + log10(m_MinValue)) ); +} + +void CChartLogarithmicAxis::PanAxis(long PanStart, long PanEnd) +{ + double StartVal = ScreenToValue(PanStart); + double EndVal = ScreenToValue(PanEnd); + + double Factor = StartVal/EndVal; + SetZoomMinMax(m_MinValue*Factor,m_MaxValue*Factor); +} + +long CChartLogarithmicAxis::GetTickPos(double TickVal) const +{ + // The tick is always at the same position, + // even if the axis is discrete. + return ValueToScreenStandard(TickVal); +} + +void CChartLogarithmicAxis::RefreshTickIncrement() +{ + // Do nothing. This is done by the user. +} + +void CChartLogarithmicAxis::RefreshFirstTick() +{ + int LogBase = (int)log10(m_MinValue); + m_dFirstTickValue = pow(10.0,LogBase); +} + +void CChartLogarithmicAxis::GetScrollbarSteps(int& iTotalSteps, int& iCurrentStep) +{ + double SeriesMin=0, SeriesMax=0; + GetSeriesMinMax(SeriesMin,SeriesMax); + + if ((m_MaxValue-m_MinValue) == 0 || (SeriesMax-SeriesMin)==0 || + (SeriesMin<=0) ) + { + iTotalSteps = 1; + iCurrentStep = 1; + } + else + { + double dStep = pow(m_MaxValue/m_MinValue,0.1); + iTotalSteps = (int)ceil(log(SeriesMax/SeriesMin)/log10(dStep)); + iCurrentStep = (int)(log(m_MinValue/SeriesMin)/log10(dStep)); + } +} + +void CChartLogarithmicAxis::SetAxisToScrollStep(int iPreviousStep, + int iCurrentStep, + bool bScrollInverted) +{ + double dStep = pow(m_MaxValue/m_MinValue,0.1); + double dFactor = pow(dStep,(iCurrentStep - iPreviousStep)); + if (bScrollInverted) + SetZoomMinMax(m_MinValue/dFactor,m_MaxValue/dFactor); + else + SetZoomMinMax(m_MinValue*dFactor,m_MaxValue*dFactor); +} diff --git a/ChartDemo/ChartCtrl/ChartLogarithmicAxis.h b/ChartDemo/ChartCtrl/ChartLogarithmicAxis.h new file mode 100644 index 0000000..de8678d --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartLogarithmicAxis.h @@ -0,0 +1,62 @@ +/* + * + * ChartLogarithmicAxis.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#ifndef _CHARTLOGARITHMICAXIS_H_ +#define _CHARTLOGARITHMICAXIS_H_ + +#include "ChartAxis.h" + +//! Specialization of a CChartAxis to display a logarithmic scale. +/** + Currently this class only allows to have a logarithmic axis with a + base of 10. +**/ +class CChartLogarithmicAxis : public CChartAxis +{ + friend CChartCtrl; + +private: + //! Constructor + CChartLogarithmicAxis(); + //! Destructor + ~CChartLogarithmicAxis(); + + double ScreenToValue(long ScreenVal) const; + void PanAxis(long PanStart, long PanEnd); + + double GetFirstTickValue() const; + bool GetNextTickValue(double dCurrentTick, double& dNextTick) const; + TChartString GetTickLabel(double TickValue) const; + long ValueToScreenStandard(double Value) const; + long ValueToScreenDiscrete(double Value) const; + long GetTickPos(double TickVal) const; + + void RefreshTickIncrement(); + void RefreshFirstTick(); + + void GetScrollbarSteps(int& iTotalSteps, int& iCurrentStep); + void SetAxisToScrollStep(int iPreviousStep, int iCurrentStep, bool bScrollInverted); + + //! Caches the value of the first tick. + double m_dFirstTickValue; +}; + +#endif // _CHARTLOGARITHMICAXIS_H_ diff --git a/ChartDemo/ChartCtrl/ChartMouseListener.h b/ChartDemo/ChartCtrl/ChartMouseListener.h new file mode 100644 index 0000000..36761d7 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartMouseListener.h @@ -0,0 +1,90 @@ +/* + * + * ChartMouseListener.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#ifndef _CHARTMOUSELISTENER_H_ +#define _CHARTMOUSELISTENER_H_ + +#pragma warning( disable : 4100 ) + +//! Listener for mouse events occuring on the chart control. +/** + This is an interface which must be implemented in order to receive + mouse notifications. You can then register your class with the chart + control by calling RegisterMouseListener. +**/ +class CChartMouseListener +{ +public: + //! Constructor + CChartMouseListener() { } + //! Destructor + virtual ~CChartMouseListener() { } + + //! Enumeration listing the type of mouse events + enum MouseEvent + { + MouseMove, + LButtonUp, + LButtonDown, + LButtonDoubleClick, + RButtonUp, + RButtonDown, + RButtonDoubleClick, + }; + + //! Virtual function to implement in order to be notified when the title is clicked. + /** + @param mouseEvent + The mouse event which occured + @param point + The screen point on which the event occured + **/ + virtual void OnMouseEventTitle(MouseEvent mouseEvent, CPoint point) { } + //! Virtual function to implement in order to be notified when an axis is clicked. + /** + @param mouseEvent + The mouse event which occured + @param point + The screen point on which the event occured + @param pAxisClicked + The axis on which the event occured + **/ + virtual void OnMouseEventAxis(MouseEvent mouseEvent, CPoint point, + CChartAxis* pAxisClicked) { } + //! Virtual function to implement in order to be notified when the legend is clicked. + /** + @param mouseEvent + The mouse event which occured + @param point + The screen point on which the event occured + **/ + virtual void OnMouseEventLegend(MouseEvent mouseEvent, CPoint point) { } + //! Virtual function to implement in order to be notified when the plotting area is clicked. + /** + @param mouseEvent + The mouse event which occured + @param point + The screen point on which the event occured + **/ + virtual void OnMouseEventPlotArea(MouseEvent mouseEvent, CPoint point) { } +}; + +#endif // _CHARTMOUSELISTENER_H_ \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartPointsArray.h b/ChartDemo/ChartCtrl/ChartPointsArray.h new file mode 100644 index 0000000..938c58e --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartPointsArray.h @@ -0,0 +1,170 @@ +/* + * + * ChartPointsArray.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#pragma once + +#include "PointsOrdering.h" + +//! Manages an array of points which supports fast resizing. +/** + This class is used internally to store the data for all the points. The data + is stored in a C-style array. The internal buffer can grow dynamically depending + on the needs. + + The class is a template class with the template parameter being the type of + the points to be stored. The points have to provide the following methods: +

  • double GetXMin()
  • +
  • double GetX()
  • +
  • double GetXMax()
  • +
  • double GetYMin()
  • +
  • double GetY()
  • +
  • double GetYMax()
+**/ +template +class CChartPointsArray +{ +public: + //! Constructor + /** + @param iResize + The size by which the internal buffer is increased when reallocation occurs + **/ + CChartPointsArray(unsigned iResize = 1000); + //! Destructor + ~CChartPointsArray(); + + //! Returns the number of points currently stored. + unsigned GetPointsCount() const { return m_iCurrentPoints; } + //! Sets the size by which the internal buffer is increased when reallocation occurs + void SetResize(int iResize) { m_iResize = iResize; } + + //! Adds a new point in the array. + /** + @param newPoint + The new point to add + **/ + void AddPoint(const T& newPoint); + //! Adds multiple points in the array. + /** + The points are added to the ones currently stored in the array. + @param pPoints + Array containing the points + @param uCount + The number of points to add + **/ + void AddPoints(T* pPoints, unsigned uCount); + //! Sets multiple points in the array. + /** + The points currently stored in the array are first removed + before adding the new points. + @param pPoints + Array containing the new points + @param uCount + The number of points to add + **/ + void SetPoints(T* pPoints, unsigned uCount); + //! Removes all the points from the array. + void Clear(); + //! Removes a certain amount of points from the begining of the series. + void RemovePointsFromBegin(unsigned Count); + //! Removes a certain amount of points from the end of the series. + void RemovePointsFromEnd(unsigned Count); + //! Retrieves the points at the specified index + T& operator[](unsigned Index); + //! Retrieves the points at the specified index + const T& operator[](unsigned Index) const; + + //! Retrieves the minimum and maximum X values of the points stored in the array. + bool GetSerieXMinMax(double& Min, double& Max) const; + //! Retrieves the minimum and maximum Y values of the points stored in the array. + bool GetSerieYMinMax(double& Min, double& Max) const; + + //! Specifies how the points should be ordered in the array. + /** + This specifies if the points should be ordered on their X values, + on their Y values or not ordered (kept in order they are added to + the control). Ordering can improve performances a lot but makes it + impossible to draw some specific curves (for instance, drawing an + ellipse is only possible if no ordering is set). + **/ + void SetOrdering(PointsOrdering newOrdering); + //! Retrieves the ordering of the points in the array. + PointsOrdering GetOrdering() const { return m_Ordering; } + //! Refreshes the point ordering. + void ReorderPoints(); + + //! Retrieves the index of the points which are between two given values. + /** + If the points are not ordered, uFirstPt will contain 0 and uLastPt + will contain the index of the last point in the array. + @param dAxisMin + The minimum value to retrieve the first visible point + @param dAxisMax + The maximum value to retrieve the last visible point + @param uFirstPt + This parameter will store the index of the first visible point + @param uLastPt + This parameter will store the index of the last visible point + @return false if no points are in the array. + **/ + bool GetVisiblePoints(double dAxisMin, double dAxisMax, + unsigned& uFirstPt, unsigned& uLastPt) const; + + + //! Returns the internal buffer of the array + T* GetInternalBuffer() const { return m_pPoints; } + +private: + //! Caches the minimum X value. + double m_dXMinVal; + //! Caches the maximum X value. + double m_dXMaxVal; + //! Caches the minimum Y value. + double m_dYMinVal; + //! Caches the maximum Y value. + double m_dYMaxVal; + + //! Recalculates the min and max values. + void RefreshMinMax(); + //! Inserts a new point in the array. + void InsertNewPoint(const T& newPoint); + //! Inserts a new point at a specific position in the array. + void InsertPointAtPos(const T& newPoint, int iPos); + //! Comparison function which compares two points based on their X values. + static int ComparePointsOnX(void const* pA, void const* pB); + //! Comparison function which compares two points based on their Y values. + static int ComparePointsOnY(void const* pA, void const* pB); + //! Implements a binary search used to find the index of a points give the X or Y value. + int BinarySearch(unsigned uLeft, unsigned uRight, double dFind) const; + + //! The array of points + T* m_pPoints; + //! The number of allocated points + unsigned m_iMaxPoints; + //! The number of points currently used + unsigned m_iCurrentPoints; + //! The size by which the array is incremented once it is full + unsigned m_iResize; + //! The ordering of the points + PointsOrdering m_Ordering; +}; + +#include "ChartPointsArray.inl" \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartPointsArray.inl b/ChartDemo/ChartCtrl/ChartPointsArray.inl new file mode 100644 index 0000000..ce4b61c --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartPointsArray.inl @@ -0,0 +1,351 @@ +/* + * + * ChartPointsArray.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + */ + +#include "ChartPointsArray.h" + +template +CChartPointsArray::CChartPointsArray(unsigned iResize) + : m_pPoints(NULL), m_iMaxPoints(iResize), m_iCurrentPoints(0), + m_iResize(iResize), m_Ordering(poXOrdering) +{ + m_pPoints = new T[iResize]; +} + +template +CChartPointsArray::~CChartPointsArray() +{ + if (m_pPoints) + { + delete[] m_pPoints; + m_pPoints = NULL; + } +} + +template +void CChartPointsArray::AddPoint(const T& newPoint) +{ + if (m_iCurrentPoints == m_iMaxPoints) + { + m_iMaxPoints += m_iResize; + T* pOldPoints = m_pPoints; + m_pPoints = new T[m_iMaxPoints]; + memcpy(m_pPoints,pOldPoints,m_iCurrentPoints*sizeof(T)); + delete[] pOldPoints; + } + + if (m_iCurrentPoints == 0) + { + m_dXMinVal = newPoint.GetXMin(); + m_dXMaxVal = newPoint.GetXMax(); + m_dYMinVal = newPoint.GetYMin(); + m_dYMaxVal = newPoint.GetYMax(); + } + else + { + if (newPoint.GetXMax() > m_dXMaxVal) m_dXMaxVal = newPoint.GetXMax(); + if (newPoint.GetXMin() < m_dXMinVal) m_dXMinVal = newPoint.GetXMin(); + if (newPoint.GetYMax() > m_dYMaxVal) m_dYMaxVal = newPoint.GetYMax(); + if (newPoint.GetYMin() < m_dYMinVal) m_dYMinVal = newPoint.GetYMin(); + } + + if (m_Ordering==poNoOrdering) + { + m_pPoints[m_iCurrentPoints] = newPoint; + m_iCurrentPoints++; + } + else + { + InsertNewPoint(newPoint); + } +} + +template +void CChartPointsArray::AddPoints(T* pPoints, + unsigned uCount) +{ + if (m_iCurrentPoints+uCount > m_iMaxPoints) + { + m_iMaxPoints = m_iCurrentPoints+uCount; + T* pOldPoints = m_pPoints; + m_pPoints = new T[m_iMaxPoints]; + memcpy(m_pPoints,pOldPoints,m_iCurrentPoints*sizeof(T)); + delete[] pOldPoints; + } + for (unsigned i=0; i +void CChartPointsArray::SetPoints(T* pPoints, + unsigned uCount) +{ + if (uCount > m_iMaxPoints) + { + if (m_pPoints) + delete[] m_pPoints; + m_pPoints = new T[uCount]; + m_iMaxPoints = uCount; + } + m_iCurrentPoints = uCount; + + for (unsigned i=0;i +void CChartPointsArray::Clear() +{ + if (m_pPoints) + delete[] m_pPoints; + m_pPoints = new T[m_iResize]; + m_iMaxPoints = m_iResize; + m_iCurrentPoints = 0; +} + +template +void CChartPointsArray::RemovePointsFromBegin(unsigned Count) +{ + ASSERT (Count < m_iCurrentPoints); + T* pSource = m_pPoints + Count; + memmove(m_pPoints, pSource, sizeof(T) * (m_iCurrentPoints-Count)); + m_iCurrentPoints -= Count; + RefreshMinMax(); +} + +template +void CChartPointsArray::RemovePointsFromEnd(unsigned Count) +{ + ASSERT (Count < m_iCurrentPoints); + m_iCurrentPoints -= Count; + RefreshMinMax(); +} + +template +T& CChartPointsArray::operator[](unsigned Index) +{ + ASSERT(Index < m_iCurrentPoints); + return m_pPoints[Index]; +} + +template +const T& CChartPointsArray::operator[](unsigned Index) const +{ + ASSERT(Index < m_iCurrentPoints); + return m_pPoints[Index]; +} + +template +bool CChartPointsArray::GetSerieXMinMax(double& Min, double& Max) const +{ + if (m_iCurrentPoints==0) + return false; + + Min = m_dXMinVal; + Max = m_dXMaxVal; + return true; +} + +template +bool CChartPointsArray::GetSerieYMinMax(double& Min, double& Max) const +{ + if (m_iCurrentPoints==0) + return false; + + Min = m_dYMinVal; + Max = m_dYMaxVal; + return true; +} + +template +void CChartPointsArray::SetOrdering(PointsOrdering newOrdering) +{ + m_Ordering = newOrdering; + ReorderPoints(); +} + +template +bool CChartPointsArray::GetVisiblePoints(double dAxisMin, + double dAxisMax, + unsigned& uFirstPt, + unsigned& uLastPt) const +{ + if (m_iCurrentPoints == 0) + return false; + + if (m_Ordering == poNoOrdering) + { + uFirstPt = 0; + uLastPt = m_iCurrentPoints - 1; + return true; + } + + uFirstPt = BinarySearch(0,m_iCurrentPoints-1,dAxisMin); + uLastPt = BinarySearch(uFirstPt,m_iCurrentPoints-1,dAxisMax); + return true; +} + +template +void CChartPointsArray::ReorderPoints() +{ + switch (m_Ordering) + { + case poNoOrdering: + break; + case poXOrdering: + qsort(m_pPoints, m_iCurrentPoints, sizeof(T), + CChartPointsArray::ComparePointsOnX); + break; + case poYOrdering: + qsort(m_pPoints, m_iCurrentPoints, sizeof(T), + CChartPointsArray::ComparePointsOnY); + break; + } +} + +template +void CChartPointsArray::InsertNewPoint(const T& newPoint) +{ + if (m_iCurrentPoints == 0) + { + m_pPoints[0] = newPoint; + m_iCurrentPoints++; + return; + } + + if (m_Ordering == poXOrdering) + { + if (newPoint.GetX() >= m_pPoints[m_iCurrentPoints-1].GetX()) + m_pPoints[m_iCurrentPoints] = newPoint; + else + { + for (unsigned i=0; i= m_pPoints[m_iCurrentPoints-1].GetY()) + m_pPoints[m_iCurrentPoints] = newPoint; + else + { + for (unsigned i=0; i +void CChartPointsArray::InsertPointAtPos(const T& newPoint, int iPos) +{ + // Find the address of the insert point + T* pPointPos = m_pPoints + iPos; + // Move all remaining points one place to the right. + memmove(pPointPos+1,pPointPos,(m_iCurrentPoints-iPos)*sizeof(T)); + // Store the new point + *pPointPos = newPoint; +} + +template +int CChartPointsArray::ComparePointsOnX(void const* pA, void const* pB) +{ + T* pPointA = (T *) pA; + T* pPointB = (T *) pB; + + if (pPointA->GetX() < pPointB->GetX()) return -1; + if (pPointA->GetX() > pPointB->GetX()) return 1; + return 0; +} + +template +int CChartPointsArray::ComparePointsOnY(void const* pA, void const* pB) +{ + T* pPointA = (T *) pA; + T* pPointB = (T *) pB; + + if (pPointA->GetY() < pPointB->GetY()) return -1; + if (pPointA->GetY() > pPointB->GetY()) return 1; + return 0; +} + +template +void CChartPointsArray::RefreshMinMax() +{ + m_dXMinVal = m_pPoints[0].GetXMin(); + m_dXMaxVal = m_pPoints[0].GetXMax(); + m_dYMinVal = m_pPoints[0].GetYMin(); + m_dYMaxVal = m_pPoints[0].GetYMax(); + for (unsigned uIndex=0; uIndex m_dXMaxVal) + m_dXMaxVal = m_pPoints[uIndex].GetXMax(); + if (m_pPoints[uIndex].GetXMin() < m_dXMinVal) + m_dXMinVal = m_pPoints[uIndex].GetXMin(); + if (m_pPoints[uIndex].GetYMax() > m_dYMaxVal) + m_dYMaxVal = m_pPoints[uIndex].GetYMax(); + if (m_pPoints[uIndex].GetYMin() < m_dYMinVal) + m_dYMinVal = m_pPoints[uIndex].GetYMin(); + } +} + +template +int CChartPointsArray::BinarySearch(unsigned uLeft, + unsigned uRight, + double dFind) const +{ + unsigned middle = uLeft + ((uRight - uLeft) /2); + double midVal = 0; + if (m_Ordering == poXOrdering) + midVal = m_pPoints[middle].GetX(); + if (m_Ordering == poYOrdering) + midVal = m_pPoints[middle].GetY(); + + if(midVal > dFind) + { + if(uLeft < middle) + return BinarySearch(uLeft,middle-1,dFind); + else + return uLeft; + } + else if(middle < uRight) + return BinarySearch(middle+1,uRight,dFind); + else + return uRight; +} + + diff --git a/ChartDemo/ChartCtrl/ChartPointsSerie.cpp b/ChartDemo/ChartCtrl/ChartPointsSerie.cpp new file mode 100644 index 0000000..685420f --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartPointsSerie.cpp @@ -0,0 +1,335 @@ +/* + * + * ChartPointsSerie.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + * History: + * - 07/07/2008: Last point of the series was not displayed. Fixed. + */ + +#include "stdafx.h" +#include "ChartPointsSerie.h" +#include "ChartCtrl.h" +#include "Math.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CChartPointsSerie::CChartPointsSerie(CChartCtrl* pParent) + : CChartXYSerie(pParent), m_iPointType(ptEllipse), m_iXPointSize(5), + m_iYPointSize(5), m_colBorder(RGB(0,0,0)) +{ +} + +CChartPointsSerie::~CChartPointsSerie() +{ + +} +void CChartPointsSerie::SetPointSize(int XSize, int YSize) +{ + m_iXPointSize = XSize; + m_iYPointSize = YSize; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartPointsSerie::SetPointType(PointType Type) +{ + m_iPointType = Type; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartPointsSerie::SetBorderColor(COLORREF Color) +{ + m_colBorder = Color; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartPointsSerie::Draw(CDC *pDC) +{ + if (!m_bIsVisible) + return; + if (!pDC->GetSafeHdc()) + return; + + CBrush NewBrush(m_SerieColor); + CPen BorderPen(PS_SOLID, 1, m_colBorder); + CBrush ShadowBrush(m_ShadowColor); + CPen ShadowPen(PS_SOLID, 1, m_ShadowColor); + CPen* pOldPen = pDC->SelectObject(&BorderPen); + CBrush* pOldBrush = pDC->SelectObject(&NewBrush); + + pDC->SetBkMode(TRANSPARENT); + //To have lines limited in the drawing rectangle : + pDC->IntersectClipRect(m_PlottingRect); + + //Draw all points that haven't been drawn yet + for (m_uLastDrawnPoint;m_uLastDrawnPoint<(int)GetPointsCount();m_uLastDrawnPoint++) + { + SChartXYPoint Point = GetPoint(m_uLastDrawnPoint); + CPoint ScreenPoint; + ValueToScreen(Point.X, Point.Y, ScreenPoint); + + CRect PointRect; + PointRect.SetRect(ScreenPoint.x-m_iXPointSize/2,ScreenPoint.y-m_iYPointSize/2,ScreenPoint.x+m_iXPointSize/2,ScreenPoint.y+m_iYPointSize/2); + CRect ShadowRect = PointRect + CSize(m_iShadowDepth,m_iShadowDepth); + + switch(m_iPointType) + { + case ptEllipse: + if (m_bShadow) + { + pOldPen = pDC->SelectObject(&ShadowPen); + pDC->SelectObject(&ShadowBrush); + pDC->Ellipse(ShadowRect); + pDC->SelectObject(&NewBrush); + pDC->SelectObject(&BorderPen); + } + pDC->Ellipse(PointRect); + break; + + case ptRectangle: + if (m_bShadow) + { + pOldPen = pDC->SelectObject(&ShadowPen); + pDC->SelectObject(&ShadowBrush); + pDC->Rectangle(ShadowRect); + pDC->SelectObject(&NewBrush); + pDC->SelectObject(&BorderPen); + } + pDC->Rectangle(PointRect); + break; + + case ptTriangle: + { + CPoint TrPoints[3]; + TrPoints[0].x = PointRect.left; + TrPoints[0].y = PointRect.bottom; + TrPoints[1].x = PointRect.right; + TrPoints[1].y = PointRect.bottom; + TrPoints[2].x = PointRect.left + (int)fabs((PointRect.left-PointRect.right)/2.0); + TrPoints[2].y = PointRect.top; + + if (m_bShadow) + { + CPoint ShadowPoints[3]; + for (int i=0;i<3;i++) + { + ShadowPoints[i] = TrPoints[i] + CSize(m_iShadowDepth,m_iShadowDepth); + } + + pOldPen = pDC->SelectObject(&ShadowPen); + pDC->SelectObject(&ShadowBrush); + pDC->Polygon(ShadowPoints,3); + pDC->SelectObject(&NewBrush); + pDC->SelectObject(&BorderPen); + } + pDC->Polygon(TrPoints,3); + } + break; + } + + } + + pDC->SelectClipRgn(NULL); + pDC->SelectObject(pOldPen); + pDC->SelectObject(pOldBrush); + DeleteObject(BorderPen); + DeleteObject(NewBrush); + DeleteObject(ShadowBrush); + DeleteObject(ShadowPen); +} + +void CChartPointsSerie::DrawAll(CDC *pDC) +{ + if (!m_bIsVisible) + return; + if (!pDC->GetSafeHdc()) + return; + + CBrush NewBrush(m_SerieColor); + CPen BorderPen(PS_SOLID, 1, m_colBorder); + CBrush ShadowBrush(m_ShadowColor); + CPen ShadowPen(PS_SOLID, 1, m_ShadowColor); + CPen* pOldPen = pDC->SelectObject(&BorderPen); + CBrush* pOldBrush = pDC->SelectObject(&NewBrush); + + unsigned uFirst=0, uLast=0; + if (!GetVisiblePoints(uFirst,uLast)) + return; + + pDC->SetBkMode(TRANSPARENT); + //To have lines limited in the drawing rectangle : + pDC->IntersectClipRect(m_PlottingRect); + + for (m_uLastDrawnPoint=uFirst;m_uLastDrawnPoint<=uLast;m_uLastDrawnPoint++) + { + SChartXYPoint Point = GetPoint(m_uLastDrawnPoint); + CPoint ScreenPoint; + ValueToScreen(Point.X, Point.Y, ScreenPoint); + + CRect PointRect; + PointRect.SetRect(ScreenPoint.x-m_iXPointSize/2,ScreenPoint.y-m_iYPointSize/2,ScreenPoint.x+m_iXPointSize/2,ScreenPoint.y+m_iYPointSize/2); + CRect ShadowRect = PointRect + CSize(m_iShadowDepth,m_iShadowDepth); + + switch(m_iPointType) + { + case ptEllipse: + if (m_bShadow) + { + pOldPen = pDC->SelectObject(&ShadowPen); + pDC->SelectObject(&ShadowBrush); + pDC->Ellipse(ShadowRect); + pDC->SelectObject(&NewBrush); + pDC->SelectObject(&BorderPen); + } + pDC->Ellipse(PointRect); + break; + + case ptRectangle: + if (m_bShadow) + { + pOldPen = pDC->SelectObject(&ShadowPen); + pDC->SelectObject(&ShadowBrush); + pDC->Rectangle(ShadowRect); + pDC->SelectObject(&NewBrush); + pDC->SelectObject(&BorderPen); + } + pDC->Rectangle(PointRect); + break; + + case ptTriangle: + { + CPoint TrPoints[3]; + TrPoints[0].x = PointRect.left; + TrPoints[0].y = PointRect.bottom; + TrPoints[1].x = PointRect.right; + TrPoints[1].y = PointRect.bottom; + TrPoints[2].x = PointRect.left + (int)fabs((PointRect.left-PointRect.right)/2.0); + TrPoints[2].y = PointRect.top; + + if (m_bShadow) + { + CPoint ShadowPoints[3]; + for (int i=0;i<3;i++) + { + ShadowPoints[i] = TrPoints[i] + CSize(m_iShadowDepth,m_iShadowDepth); + } + + pOldPen = pDC->SelectObject(&ShadowPen); + pDC->SelectObject(&ShadowBrush); + pDC->Polygon(ShadowPoints,3); + pDC->SelectObject(&NewBrush); + pDC->SelectObject(&BorderPen); + } + pDC->Polygon(TrPoints,3); + } + break; + } + } + + pDC->SelectClipRgn(NULL); + pDC->SelectObject(pOldPen); + pDC->SelectObject(pOldBrush); + DeleteObject(BorderPen); + DeleteObject(NewBrush); + DeleteObject(ShadowBrush); + DeleteObject(ShadowPen); +} + +void CChartPointsSerie::DrawLegend(CDC *pDC, const CRect& rectBitmap) const +{ + if (m_strSerieName== _T("")) + return; + + CRect PointRect(0,0,m_iXPointSize,m_iYPointSize); + if ( (rectBitmap.Height()>m_iYPointSize) && (rectBitmap.Width()>m_iXPointSize) ) + { + int XOffset = rectBitmap.left + rectBitmap.Width()/2 - m_iXPointSize/2; + int YOffset = rectBitmap.top + rectBitmap.Height()/2 - m_iYPointSize/2; + PointRect.OffsetRect(XOffset,YOffset); + } + else + PointRect = rectBitmap; + + CBrush NewBrush(m_SerieColor); + CBrush* pOldBrush = pDC->SelectObject(&NewBrush); + + switch(m_iPointType) + { + case ptEllipse: + pDC->Ellipse(PointRect); + break; + + case ptRectangle: + pDC->Rectangle(PointRect); + break; + + case ptTriangle: + { + CPoint TrPoints[3]; + TrPoints[0].x = PointRect.left; + TrPoints[0].y = PointRect.bottom; + TrPoints[1].x = PointRect.right; + TrPoints[1].y = PointRect.bottom; + TrPoints[2].x = PointRect.left + (int)fabs((PointRect.left-PointRect.right)/2.0); + TrPoints[2].y = PointRect.top; + + pDC->Polygon(TrPoints,3); + } + break; + } + + pDC->SelectObject(pOldBrush); + DeleteObject(NewBrush); +} + +bool CChartPointsSerie::IsPointOnSerie(const CPoint& screenPoint, unsigned& uIndex) const +{ + uIndex = INVALID_POINT; + if (!m_bIsVisible) + return false; + + unsigned uFirst=0, uLast=0; + if (!GetVisiblePoints(uFirst, uLast)) + return false; + + bool bResult = false; + for (unsigned i=uFirst ; i < uLast ; i++) + { + SChartXYPoint Point = GetPoint(i); + CPoint ValuePoint; + ValueToScreen(Point.X, Point.Y, ValuePoint); + + int xDist = abs(screenPoint.x - ValuePoint.x); + int yDist = abs(screenPoint.y - ValuePoint.y); + if (xDist<=5 && yDist<=5) + { + uIndex = i; + bResult = true; + break; + } + } + return bResult; +} + diff --git a/ChartDemo/ChartCtrl/ChartPointsSerie.h b/ChartDemo/ChartCtrl/ChartPointsSerie.h new file mode 100644 index 0000000..5faafef --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartPointsSerie.h @@ -0,0 +1,117 @@ +/* + * + * ChartPointsSerie.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#if !defined(AFX_CHARTPOINTSSERIE_H__F66C180F_F04C_4E2D_878C_08BDBCE91863__INCLUDED_) +#define AFX_CHARTPOINTSSERIE_H__F66C180F_F04C_4E2D_878C_08BDBCE91863__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "ChartXYSerie.h" + +//! Specialization of a CChartSerie to display a points series. +/** + The data points are simply displayed as independant points. +**/ +class CChartPointsSerie : public CChartXYSerie +{ +public: + //! The different point shapes + enum PointType + { + ptEllipse=0, + ptRectangle=1, + ptTriangle=2 + }; + + //! Sets the width and height of each points + void SetPointSize(int XSize, int YSize); + //! Retrieves the width and height of each points + void GetPointSize(int& XSize, int& YSize) const + { + XSize = m_iXPointSize; + YSize = m_iYPointSize; + } + //! Sets the points shape + void SetPointType(PointType Type); + //! Returns the points shape + PointType GetPointType() const { return m_iPointType; } + + //! Sets the border color of the points + void SetBorderColor(COLORREF Color); + //! Returns the border color of the points + COLORREF GetBorderColor() { return m_colBorder; } + + //! Constructor + CChartPointsSerie(CChartCtrl* pParent); + //! Destructor + virtual ~CChartPointsSerie(); + + //! Check whether a screen point is on the series. + /** + @param screenPoint + The screen point to test + @param uIndex + If the point is close to a specific point of the series, its index is stored here. + @return true if the point is on the series + **/ + bool IsPointOnSerie(const CPoint& screenPoint, unsigned& uIndex) const; + +private: + //! Draws the legend icon for the series. + /** + This pure virtual function should be overriden by child classes. + @param pDC + The device context used to draw + @param rectBitmap + The rectangle in which to draw the legend icon + **/ + void DrawLegend(CDC* pDC, const CRect& rectBitmap) const; + + //! Draws the most recent points of the series. + /** + This pure virtual function should be overriden by child classes. + This function should only draw the points that were not previously + drawn. + @param pDC + The device context used to draw + **/ + void Draw(CDC* pDC); + //! Redraws the full series. + /** + This pure virtual function should be overriden by child classes. + @param pDC + The device context used to draw + **/ + void DrawAll(CDC *pDC); + + //! Width of the points + int m_iXPointSize; + //! Height of the points + int m_iYPointSize; + //! Shape of the points + PointType m_iPointType; + //! The border color + COLORREF m_colBorder; +}; + +#endif // !defined(AFX_CHARTPOINTSSERIE_H__F66C180F_F04C_4E2D_878C_08BDBCE91863__INCLUDED_) diff --git a/ChartDemo/ChartCtrl/ChartScrollBar.cpp b/ChartDemo/ChartCtrl/ChartScrollBar.cpp new file mode 100644 index 0000000..f5d111c --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartScrollBar.cpp @@ -0,0 +1,222 @@ +/* + * + * ChartScrollBar.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#include "stdafx.h" +#include "ChartScrollBar.h" +#include "ChartAxis.h" +#include "ChartCtrl.h" +#include "math.h" + +CChartScrollBar::CChartScrollBar(CChartAxis* pParentAxis) + : CScrollBar(), m_pParentAxis(pParentAxis), m_bEnabled(false), + m_bAutoHide(true) +{ +} + +CChartScrollBar::~CChartScrollBar() +{ +} + +void CChartScrollBar::CreateScrollBar(const CRect& PlottingRect) +{ + CRect Temp = PlottingRect; + Temp.top++; Temp.left++; + + DWORD dwStyle = SBS_HORZ | WS_CHILD; + if (m_pParentAxis->IsHorizontal()) + { + if (m_pParentAxis->IsSecondary()) + dwStyle |= SBS_TOPALIGN; + else + dwStyle += SBS_BOTTOMALIGN; + } + else + { + if (m_pParentAxis->IsSecondary()) + dwStyle |= SBS_VERT | SBS_RIGHTALIGN; + else + dwStyle += SBS_VERT | SBS_LEFTALIGN; + } + CScrollBar::Create(dwStyle, Temp, m_pParentAxis->m_pParentCtrl,100); + SCROLLINFO info; + info.cbSize = sizeof(SCROLLINFO); + info.fMask = SIF_ALL; + info.nMin = 1; + info.nMax = 1; + info.nPage = 1; + info.nPos = 1; + CScrollBar::SetScrollInfo(&info); + +} + +bool CChartScrollBar::IsScrollInverted() const +{ + bool bInverted = false; + if (m_pParentAxis->IsInverted() && m_pParentAxis->IsHorizontal()) + bInverted = true; + if (!m_pParentAxis->IsInverted() && !m_pParentAxis->IsHorizontal()) + bInverted = true; + + return bInverted; +} + +void CChartScrollBar::Refresh() +{ + int iTotalSteps = 0; + int iCurrentStep = 0; + m_pParentAxis->GetScrollbarSteps(iTotalSteps,iCurrentStep); + + SCROLLINFO info; + info.cbSize = sizeof(SCROLLINFO); + info.fMask = SIF_ALL; + + info.nMin = 0; + info.nMax = iTotalSteps-1; + info.nPage = 10; + info.nPos = iCurrentStep; + + if (IsScrollInverted()) + info.nPos = iTotalSteps - 9 - iCurrentStep; + else + info.nPos = iCurrentStep; + CScrollBar::SetScrollInfo(&info); +} + +void CChartScrollBar::OnHScroll(UINT nSBCode, UINT nPos) +{ + int MinPos; + int MaxPos; + int PreviousPos = CScrollBar::GetScrollPos(); + CScrollBar::GetScrollRange(&MinPos, &MaxPos); + int CurPos = PreviousPos; + + bool bUpdate = true; + switch (nSBCode) + { + case SB_LEFT: + CurPos = 0; + break; + case SB_RIGHT: + CurPos = MaxPos; + break; + case SB_ENDSCROLL: + bUpdate = false; + break; + case SB_LINELEFT: + if (CurPos > MinPos) + CurPos--; + break; + case SB_LINERIGHT: + if (CurPos < MaxPos-9) + CurPos++; + break; + case SB_PAGELEFT: + if (CurPos > MinPos) + CurPos = max(MinPos, CurPos - 10); + break; + case SB_PAGERIGHT: + if (CurPos < MaxPos-9) + CurPos = min(MaxPos, CurPos + 10); + break; + case SB_THUMBPOSITION: + CurPos = nPos; + break; + case SB_THUMBTRACK: + CurPos = nPos; + break; + } + + if (bUpdate) + { + // Set the new position of the thumb (scroll box). + CScrollBar::SetScrollPos(CurPos); + MoveAxisToPos(PreviousPos,CurPos); + } +} + +void CChartScrollBar::OnVScroll(UINT nSBCode, UINT nPos) +{ + int MinPos; + int MaxPos; + int PreviousPos = CScrollBar::GetScrollPos(); + CScrollBar::GetScrollRange(&MinPos, &MaxPos); + int CurPos = PreviousPos; + bool bUpdate = true; + + switch (nSBCode) + { + case SB_BOTTOM: + CurPos = MaxPos; + break; + case SB_TOP: + CurPos = 0; + break; + case SB_ENDSCROLL: + bUpdate = false; + break; + case SB_LINEDOWN: + if (CurPos < MaxPos-9) + CurPos++; + break; + case SB_LINEUP: + if (CurPos > MinPos) + CurPos--; + break; + case SB_PAGEUP: + if (CurPos > MinPos) + CurPos = max(MinPos, CurPos - 10); + break; + case SB_PAGEDOWN: + if (CurPos < MaxPos-9) + CurPos = min(MaxPos, CurPos + 10); + break; + case SB_THUMBPOSITION: + CurPos = nPos; + break; + case SB_THUMBTRACK: + CurPos = nPos; + break; + } + + if (bUpdate) + { + // Set the new position of the thumb (scroll box). + CScrollBar::SetScrollPos(CurPos); + MoveAxisToPos(PreviousPos,CurPos); + } +} + +void CChartScrollBar::MoveAxisToPos(int PreviousPos, int CurPos) +{ + m_pParentAxis->SetAxisToScrollStep(PreviousPos,CurPos,IsScrollInverted()); +} + +void CChartScrollBar::OnMouseEnter() +{ + if (m_bEnabled && m_bAutoHide) + ShowWindow(SW_SHOW); +} + +void CChartScrollBar::OnMouseLeave() +{ + if (m_bEnabled && m_bAutoHide) + ShowWindow(SW_HIDE); +} diff --git a/ChartDemo/ChartCtrl/ChartScrollBar.h b/ChartDemo/ChartCtrl/ChartScrollBar.h new file mode 100644 index 0000000..b7425a1 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartScrollBar.h @@ -0,0 +1,75 @@ +/* + * + * ChartScrollBar.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#pragma once + +class CChartAxis; + +//! Class which manages the interaction with the axis scroll bar. +/** + This class is used internally by the CChartAxis class. +**/ +class CChartScrollBar : public CScrollBar +{ +friend CChartAxis; + +public: + //! Creates the scroll bar within a specified rectangle. + void CreateScrollBar(const CRect& PlottingRect); + + //! Called on horizontal scrolling. + void OnHScroll(UINT nSBCode, UINT nPos); + //! Called on vertical scrolling. + void OnVScroll(UINT nSBCode, UINT nPos); + //! Refreshes the scroll bar position. + void Refresh(); + + //! Enables/disables the scroll bar. + void SetEnabled(bool bEnabled) { m_bEnabled = bEnabled; } + //! Returns true if the scroll bar is enabled + bool GetEnabled() const { return m_bEnabled; } + //! Enables/disables the auto-hide mode. + /** + In auto-hide mode, the scroll bar is not visible unless the mouse + is over the region of the scroll bar. + **/ + void SetAutoHide(bool bAutoHide) { m_bAutoHide = bAutoHide; } + //! Returns true if the auto-hide mode is activated. + bool GetAutoHide() const { return m_bAutoHide; } + + //! Called when the mouse enters the scroll bar area. + void OnMouseEnter(); + //! Called when the mouse leaves the scroll bar area. + void OnMouseLeave(); + +private: + //! Constructor + CChartScrollBar(CChartAxis* pParentAxis); + //! Destructor + ~CChartScrollBar(); + + bool IsScrollInverted() const; + void MoveAxisToPos(int PreviousPos, int CurPos); + + CChartAxis* m_pParentAxis; + bool m_bEnabled; + bool m_bAutoHide; +}; diff --git a/ChartDemo/ChartCtrl/ChartSerie.cpp b/ChartDemo/ChartCtrl/ChartSerie.cpp new file mode 100644 index 0000000..eee56a9 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartSerie.cpp @@ -0,0 +1,150 @@ +/* + * + * ChartSerie.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * History: + * - 11/08/2006: Management of the auto axis now done in the axis. Series Register + * Unregister themselves to their respective axes . + * - 29/02/2008: Taking into account that RefreshAutoAxis doesn't refresh the control. + * - 01/03/2008: RemovePointsFromBegin and RemovePointsFromEnd functions added. + * - 08/03/2008: AddPoints function added (thanks to Bruno Lavier). + * - 11/03/2008: Min and max values are now cached. + * - 14/03/2008: Series can be ordered. Speed improvement done in that case. + * - 13/08/2008: Bug fix: calling AddPoint was not drawing the new points. + * - 27/11/2008: Points are now stored into the CChartPointsArray class instead of + * std::vector for efficiency. + * + */ + +#include "stdafx.h" +#include "ChartCtrl.h" +#include "ChartSerie.h" +#include "ChartAxis.h" + +#include "Math.h" +#include + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +unsigned CChartSerie::m_uNextFreeId = 0; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CChartSerie::CChartSerie(CChartCtrl* pParent) +{ + m_pParentCtrl = pParent; +// m_uLastDrawnPoint = 0; + m_strSerieName = _T(""); + + m_pHorizontalAxis = m_pVerticalAxis = NULL; + m_uSerieId = m_uNextFreeId; + m_uNextFreeId++; + + m_bIsVisible = true; + m_bShadow = false; + m_SerieColor = RGB(0, 0, 0); + m_ShadowColor = RGB(150,150,150); + m_iShadowDepth = 2; + + m_bMouseClickNotifications = true; + m_bMouseMoveNotifications = false; +} + +CChartSerie::~CChartSerie() +{ + m_pHorizontalAxis->UnregisterSeries(this); + m_pVerticalAxis->UnregisterSeries(this); +} + +//void CChartSerie::SetSeriesOrdering(CChartPointsArray::PointsOrdering newOrdering) +//{ +// m_vPoints.SetOrdering(newOrdering); +//} + +void CChartSerie::SetName(const TChartString& NewName) +{ + m_strSerieName = NewName; + m_pParentCtrl->RefreshCtrl(); +} + +double CChartSerie::XScreenToValue(long XScreenCoord) const +{ + return m_pHorizontalAxis->ScreenToValue(XScreenCoord); +} + +double CChartSerie::YScreenToValue(long YScreenCoord) const +{ + return m_pVerticalAxis->ScreenToValue(YScreenCoord); +} + +void CChartSerie::ValueToScreen(double XValue, double YValue, CPoint &ScreenPoint) const +{ + ScreenPoint.x = m_pHorizontalAxis->ValueToScreen(XValue); + ScreenPoint.y = m_pVerticalAxis->ValueToScreen(YValue); +} + +void CChartSerie::SetVisible(bool bVisible) +{ + m_bIsVisible = bVisible; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartSerie::SetColor(COLORREF NewColor) +{ + m_SerieColor = NewColor; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartSerie::SetShadowColor(COLORREF NewColor) +{ + m_ShadowColor = NewColor; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartSerie::EnableShadow(bool bEnable) +{ + m_bShadow = bEnable; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartSerie::SetShadowDepth(int Depth) +{ + m_iShadowDepth = Depth; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartSerie::EnableMouseNotifications(bool bClickEnabled, bool bMoveEnabled) +{ + m_bMouseClickNotifications = bClickEnabled; + m_bMouseMoveNotifications = bMoveEnabled; +} + +void CChartSerie::RefreshAutoAxes(bool bForceRefresh) +{ + m_pParentCtrl->EnableRefresh(false); + m_pHorizontalAxis->RefreshAutoAxis(); + m_pVerticalAxis->RefreshAutoAxis(); + if (bForceRefresh) + m_pParentCtrl->RefreshCtrl(); + m_pParentCtrl->EnableRefresh(true); +} diff --git a/ChartDemo/ChartCtrl/ChartSerie.h b/ChartDemo/ChartCtrl/ChartSerie.h new file mode 100644 index 0000000..a5ce223 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartSerie.h @@ -0,0 +1,283 @@ +/* + * + * ChartSerie.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#if !defined(AFX_CHARTSERIE_H__FFCF0E32_10E7_4A4D_9FF3_3C6177EDE4B1__INCLUDED_) +#define AFX_CHARTSERIE_H__FFCF0E32_10E7_4A4D_9FF3_3C6177EDE4B1__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +#define INVALID_POINT UINT_MAX + +#include "ChartAxis.h" +#include "ChartSeriesMouseListener.h" + +#include +#include "ChartString.h" + +class CChartLegend; +class CChartCtrl; + +#define INVALID_POINT UINT_MAX + +//! Abstract class that provides a common "interface" for all series in the control +/** + The class doesn't manipulate points (the type of point is unknown at this + level in the class hierarchy) but it provides all other functionalities + which are independant of the point type. + + The drawing of the series is made through pure virtual functions which + should be implemented by derived classes. + + Each series is identified by an Id. +**/ +class CChartSerie +{ + friend CChartCtrl; + friend CChartLegend; + +public: + //! Returns the number of points in the series. + virtual unsigned GetPointsCount() const = 0; + + //! Returns the screen coordinate of a specific point + virtual CPoint GetPointScreenCoord(unsigned uPointIndex) = 0; + + //! Retrieves the minimum and maxium Y values of the series. + /** + @param Min + Minimum value will be stored in this parameter + @param Max + Maximum value will be stored in this parameter + @return + false if the series doesn't contain data or is invisible + **/ + virtual bool GetSerieYMinMax(double& Min, double& Max) const = 0; + //! Retrieves the minimum and maxium X values of the series. + /** + @param Min + Minimum value will be stored in this parameter + @param Max + Maximum value will be stored in this parameter + @return + false if the series doesn't contain data or is invisible + **/ + virtual bool GetSerieXMinMax(double& Min, double& Max) const = 0; + //! Retrieves the minimum and maxium screen X values of the series. + /** + @param Min + Minimum value will be stored in this parameter + @param Max + Maximum value will be stored in this parameter + @return + false if the series doesn't contain data or is invisible + **/ + virtual bool GetSerieXScreenMinMax(double& Min, double& Max) const = 0; + //! Retrieves the minimum and maxium screen Y values of the series. + /** + @param Min + Minimum value will be stored in this parameter + @param Max + Maximum value will be stored in this parameter + @return + false if the series doesn't contain data or is invisible + **/ + virtual bool GetSerieYScreenMinMax(double& Min, double& Max) const = 0; + + //! Sets the name of the series, which is displayed in the legend. + void SetName(const TChartString& NewName); + //! Returns the name of the series. + TChartString GetName() const { return m_strSerieName; } + + //! Converts any data point into its relative screen point. + /** + @param XValue + The X value of the data point + @param YValue + The Y value of the data point + @param ScreenPoint + The screen point will be stored in the parameter + **/ + void ValueToScreen(double XValue, double YValue, CPoint& ScreenPoint) const; + //! Converts an Y screen value into its relative Y data value. + double YScreenToValue(long YScreenCoord) const; + //! Converts an Xscreen value into its relative X data value. + double XScreenToValue(long XScreenCoord) const; + + //! Constructor + CChartSerie(CChartCtrl* pParent); + //! Destructor + virtual ~CChartSerie(); + + //! Specifies if the series is visible or not. + /** + An invisible series won't affect automatic axis: it is considered + as if it was not in the control. + **/ + void SetVisible(bool bVisible); + //! Returns true if the series is visible. + bool IsVisible() const { return m_bIsVisible; } + + //! Returns the color of the series. + COLORREF GetColor() const { return m_SerieColor; } + //! Sets the color of the series. + void SetColor(COLORREF NewColor); + //! Returns the color of the shadow. + COLORREF GetShadowColor() const { return m_ShadowColor; } + //! Sets the color of the shadow. + void SetShadowColor(COLORREF NewColor); + //! Enables or disables the shadow for the series. + void EnableShadow(bool bEnable); + //! Sepcifies the depth (in pixels) of the shadow. + void SetShadowDepth(int Depth); + + //! Tests if a certain screen point is on the series. + /** + This function should be overidden by all child classes. + @param screenPoint + The screen point to test + @param uIndex + If the point is close to a specific point of the series, its index is stored here. + @return true if the point is on the series + **/ + virtual bool IsPointOnSerie(const CPoint& screenPoint, unsigned& uIndex) const = 0; + + //! Returns the series Id. + unsigned GetSerieId() const { return m_uSerieId; } + //! Enables or disables certain mouse notifications on the series. + /** + Checking if a point is on the series could degrade performances if + it has to be done for each mouse event. This function allows to disable + certain notifications, in which case the test won't be done. By default + the series reacts on mouse clicks but not on mouse moves. + @param bClickEnabled + Specifies if the series reacts on mouse clicks. + @param bMoveEnabled + Specifies if the series reacts on mouse moves. + **/ + void EnableMouseNotifications(bool bClickEnabled, bool bMoveEnabled); + +protected: + //! Refreshes the automatic axes associated with this series + void RefreshAutoAxes(bool bForceRefresh); + //! Returns the first and last visible points of the series. + /** + This function only works if ordering is enabled. + @param uFirst + The index of the first visible point is stored in this argument + @param uLast + The index of the last visible point is stored in this argument + @return false if the series has no ordering or no data points. + **/ + virtual bool GetVisiblePoints(unsigned& uFirst, unsigned& uLast) const = 0; + + //! Draws the legend icon for the series. + /** + This pure virtual function should be overriden by child classes. + @param pDC + The device context used to draw + @param rectBitmap + The rectangle in which to draw the legend icon + **/ + virtual void DrawLegend(CDC* pDC, const CRect& rectBitmap) const =0; + + //! Draws the most recent points of the series. + /** + This pure virtual function should be overriden by child classes. + This function should only draw the points that were not previously + drawn. + @param pDC + The device context used to draw + **/ + virtual void Draw(CDC* pDC) =0; + //! Redraws the full series. + /** + This pure virtual function should be overriden by child classes. + @param pDC + The device context used to draw + **/ + virtual void DrawAll(CDC *pDC) =0; + //! Draws the labels of the series. + /** + This pure virtual function should be overriden by child classes. + @param pDC + The device context used to draw + **/ + virtual void DrawLabels(CDC* pDC) =0; + + //! Called when a mouse event is detected on the chart + /** + This pure virtual function should be overriden by child classes. + @param mouseEvent + The event that occured on the control + @param screenPoint + The screen point on which the event occured + @return true if the event occured on the series. + **/ + virtual bool OnMouseEvent(CChartMouseListener::MouseEvent mouseEvent, + const CPoint& screenPoint) = 0; + + //! Returns true if the series reacts on mouse moves. + bool NotifyMouseMoveEnabled() { return m_bMouseMoveNotifications; } + //! Returns true if the series reacts on mouse clicks. + bool NotifyMouseClickEnabled() { return m_bMouseClickNotifications; } + + //! The parent charting control. + CChartCtrl* m_pParentCtrl; + //! The related vertical axis. + CChartAxis* m_pVerticalAxis; + //! The related horizontal axis. + CChartAxis* m_pHorizontalAxis; + + //! The series name displayed in the legend. + TChartString m_strSerieName; + + //! Specifies if the series is visible. + bool m_bIsVisible; + //! Specifies if the series has shadow enabled. + bool m_bShadow; + //! Color of the series + COLORREF m_SerieColor; + //! Color of the shadow + COLORREF m_ShadowColor; + //! Depth (in pixels) of the shadow + int m_iShadowDepth; + //! The rectangle in which the series should be drawn. + CRect m_PlottingRect; + +private: + //! Sets the plotting rectangle. + void SetPlottingRect(const CRect& plottingRect) { m_PlottingRect = plottingRect; } + + //! The next available series Id + static unsigned m_uNextFreeId; + //! The series Id + unsigned m_uSerieId; + + //! Specifies if the series reacts on mouse clicks. + bool m_bMouseClickNotifications; + //! Specifies if the series reacts on mouse moves. + bool m_bMouseMoveNotifications; +}; + +#endif // !defined(AFX_CHARTSERIE_H__FFCF0E32_10E7_4A4D_9FF3_3C6177EDE4B1__INCLUDED_) diff --git a/ChartDemo/ChartCtrl/ChartSerieBase.h b/ChartDemo/ChartCtrl/ChartSerieBase.h new file mode 100644 index 0000000..af01f91 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartSerieBase.h @@ -0,0 +1,231 @@ +/* + * + * ChartSerieBase.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#pragma once + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "ChartSerie.h" +#include "ChartAxis.h" +#include "ChartPointsArray.h" +#include "ChartLabel.h" +#include "ChartBalloonLabel.h" +#include "ChartSeriesMouseListener.h" + +#include +#include "ChartString.h" +#include "PointsOrdering.h" + +class CChartLegend; + + +//! Base class for all series of the control +/** + This class inherits from CChartSeries and introduces the concept of + points through the template parameter. + + This class is much more than a simple base class. It already store + all the data points and provide utility functions to manipulate them. +**/ +template +class CChartSerieBase : public CChartSerie +{ + friend CChartCtrl; + friend CChartLegend; + +public: + //! Adds a single data point to the series. + void AddPoint(const T& newPoint); + //! Adds an array of points to the series. + /** + Points which were already present in the series are kept. + @param pPoints + Array of the new points + @param Count + Size of the array + **/ + void AddPoints(T* pPoints, unsigned Count); + //! Retrieves the point at the specified index. + /** + @param index + The index of the point to retrieve + **/ + const T& GetPoint(unsigned index) const; + //! Sets an array of points to the series. + /** + Points which were already present in the series are discarded. + @param pPoints + Array of the new points + @param Count + Size of the array + **/ + void SetPoints(T* pPoints, unsigned Count); + //! Removes a certain amount of points from the begining of the series. + void RemovePointsFromBegin(unsigned Count); + //! Removes a certain amount of points from the end of the series. + void RemovePointsFromEnd(unsigned Count); + //! Removes all points from the series. + void ClearSerie(); + + //! Returns the number of points in the series. + unsigned GetPointsCount() const { return m_vPoints.GetPointsCount(); } + + //! Retrieves the minimum and maxium Y values of the series. + /** + @param Min + Minimum value will be stored in this parameter + @param Max + Maximum value will be stored in this parameter + @return + false if the series doesn't contain data or is invisible + **/ + bool GetSerieYMinMax(double& Min, double& Max) const; + //! Retrieves the minimum and maxium X values of the series. + /** + @param Min + Minimum value will be stored in this parameter + @param Max + Maximum value will be stored in this parameter + @return + false if the series doesn't contain data or is invisible + **/ + bool GetSerieXMinMax(double& Min, double& Max) const; + //! Retrieves the minimum and maxium screen X values of the series. + /** + @param Min + Minimum value will be stored in this parameter + @param Max + Maximum value will be stored in this parameter + @return + false if the series doesn't contain data or is invisible + **/ + bool GetSerieXScreenMinMax(double& Min, double& Max) const; + //! Retrieves the minimum and maxium screen Y values of the series. + /** + @param Min + Minimum value will be stored in this parameter + @param Max + Maximum value will be stored in this parameter + @return + false if the series doesn't contain data or is invisible + **/ + bool GetSerieYScreenMinMax(double& Min, double& Max) const; + + //! Creates and attaches a balloon label on a point of the series. + /** + This functions specifies a static text to display in the label. + @param uPointIndex + The index of the point on which the label should be attached + @param strLabelText + The text of the label + @return the created CChartBalloonLabel + **/ + CChartBalloonLabel* CreateBalloonLabel(unsigned uPointIndex, const TChartString& strLabelText); + //! Creates and attaches a balloon label on a point of the series. + /** + This functions specifies a CChartLabelProvider object which is used to + supply the text of the label. This is useful if you want more flexibility + for the text of the label (display information about the point value for + instance). + @param uPointIndex + The index of the point on which the label should be attached + @param pLabelProvider + Object providing the text displayed on the label + @return the created CChartBalloonLabel + **/ + CChartBalloonLabel* CreateBalloonLabel(unsigned uPointIndex, CChartLabelProvider* pLabelProvider); + //! Attaches a custom label on a point of the series. + /** + @param uPointIndex + The index of the point on which the label should be attached + @param pLabel + The label to attach to the point + **/ + void AttachCustomLabel(unsigned uPointIndex, CChartLabel* pLabel); + + //! Constructor + CChartSerieBase(CChartCtrl* pParent); + //! Destructor + virtual ~CChartSerieBase(); + + //! Specifies how the points should be ordered in the series. + /** + This specifies if the points should be ordered on their X values, + on their Y values or not ordered (kept in order they are added to + the control). Ordering can improve performances a lot but makes it + impossible to draw some specific curves (for instance, drawing an + ellipse is only possible if no ordering is set). + **/ + virtual void SetSeriesOrdering(PointsOrdering newOrdering); + + //! Retrieves the screen point of a specific data point + /** + @param uPointIndex + The index of the point for which to retrieve the screen point + @return the screen point + **/ + CPoint GetPointScreenCoord(unsigned uPointIndex); + + //! Register a series mouse listener on this series + /** + @param pListener + The listener to register + **/ + void RegisterMouseListener(CChartSeriesMouseListener* pListener); + //! Unregister the series mouse listener for this series + void UnregisterMouseListener(); + +protected: + //! Returns the first and last visible points of the series. + /** + This function only works if ordering is enabled. + @param uFirst + The index of the first visible point is stored in this argument + @param uLast + The index of the last visible point is stored in this argument + @return false if the series has no ordering or no data points. + **/ + bool GetVisiblePoints(unsigned& uFirst, unsigned& uLast) const; + + //! Called by the control to check if an event occured on the series. + bool OnMouseEvent(CChartMouseListener::MouseEvent mouseEvent, + const CPoint& screenPoint); + + //! The helper class containing all the data points. + CChartPointsArray m_vPoints; + //! Index of the last point drawn + unsigned m_uLastDrawnPoint; + +private: + //! Draws the labels of the series. + void DrawLabels(CDC* pDC); + + typedef std::map*> TLabelMap; + //! Map containing the labels of the series. + TLabelMap m_mapLabels; + + CChartSeriesMouseListener* m_pMouseListener; +}; + +#include "ChartSerieBase.inl" + diff --git a/ChartDemo/ChartCtrl/ChartSerieBase.inl b/ChartDemo/ChartCtrl/ChartSerieBase.inl new file mode 100644 index 0000000..98aa017 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartSerieBase.inl @@ -0,0 +1,340 @@ +/* + * + * ChartSerieBase.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#include "ChartSerieBase.h" +#include "ChartAxis.h" +#include "ChartCtrl.h" +#include "ChartLabel.h" + +#include "Math.h" +#include + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +template +CChartSerieBase::CChartSerieBase(CChartCtrl* pParent) : CChartSerie(pParent) +{ + m_uLastDrawnPoint = 0; + m_pMouseListener = NULL; +} + +template +CChartSerieBase::~CChartSerieBase() +{ + TLabelMap::iterator iter = m_mapLabels.begin(); + for (iter; iter!=m_mapLabels.end(); iter++) + { + delete iter->second; + } +} + +template +void CChartSerieBase::SetSeriesOrdering(PointsOrdering newOrdering) +{ + m_vPoints.SetOrdering(newOrdering); +} + + +template +void CChartSerieBase::AddPoint(const T& newPoint) +{ + m_vPoints.AddPoint(newPoint); + RefreshAutoAxes(false); + + CDC* pDC = m_pParentCtrl->GetDC(); + Draw(pDC); + m_pParentCtrl->Invalidate(); +} + +template +void CChartSerieBase::AddPoints(T* pPoints, unsigned Count) +{ + m_vPoints.AddPoints(pPoints, Count); + RefreshAutoAxes(false); + + CDC* pDC = m_pParentCtrl->GetDC(); + Draw(pDC); + m_pParentCtrl->Invalidate(); +} + +template +const T& CChartSerieBase::GetPoint(unsigned Index) const +{ + return m_vPoints[Index]; +} + +template +void CChartSerieBase::SetPoints(T* pPoints, unsigned Count) +{ + m_vPoints.SetPoints(pPoints, Count); + RefreshAutoAxes(true); +} + +template +void CChartSerieBase::RemovePointsFromBegin(unsigned Count) +{ + m_vPoints.RemovePointsFromBegin(Count); + // Remove all the labels associated with those points + for (unsigned i=0; i<=Count; i++) + { + TLabelMap::iterator iter = m_mapLabels.find(i); + if (iter != m_mapLabels.end()) + { + delete iter->second; + m_mapLabels.erase(iter); + } + } + + RefreshAutoAxes(true); +} + +template +void CChartSerieBase::RemovePointsFromEnd(unsigned Count) +{ + unsigned uPtsCount = m_vPoints.GetPointsCount(); + + m_vPoints.RemovePointsFromEnd(Count); + // Remove all the labels associated with those points + unsigned uStart = uPtsCount - Count; + for (unsigned i=0; i<=Count; i++) + { + TLabelMap::iterator iter = m_mapLabels.find(uStart + i); + if (iter != m_mapLabels.end()) + { + delete iter->second; + m_mapLabels.erase(iter); + } + } + + RefreshAutoAxes(true); +} + +template +void CChartSerieBase::ClearSerie() +{ + m_vPoints.Clear(); + TLabelMap::iterator iter = m_mapLabels.begin(); + for (iter; iter!=m_mapLabels.end(); iter++) + { + delete iter->second; + } + m_mapLabels.clear(); + m_uLastDrawnPoint = 0; + + RefreshAutoAxes(true); +} + +template +bool CChartSerieBase::GetSerieXMinMax(double &Min, double &Max) const +{ + if (!IsVisible()) + return false; + return m_vPoints.GetSerieXMinMax(Min, Max); +} + +template +bool CChartSerieBase::GetSerieYMinMax(double &Min, double &Max) const +{ + if (!IsVisible()) + return false; + return m_vPoints.GetSerieYMinMax(Min, Max); +} + +template +bool CChartSerieBase::GetSerieXScreenMinMax(double& Min, double& Max) const +{ + if (!IsVisible()) + return false; + if (m_vPoints.GetOrdering() != poYOrdering) + return false; + + unsigned first=0, last=0; + bool bRes = GetVisiblePoints(first, last); + if (!bRes) + return false; + + Min = m_vPoints[first].GetXMin(); + Max = m_vPoints[first].GetXMax(); + for (unsigned i=first; i Max) + Max = m_vPoints[i].GetXMax(); + } + return true; +} + +template +bool CChartSerieBase::GetSerieYScreenMinMax(double& Min, double& Max) const +{ + if (!IsVisible()) + return false; + if (m_vPoints.GetOrdering() != poXOrdering) + return false; + + unsigned first=0, last=0; + bool bRes = GetVisiblePoints(first, last); + if (!bRes) + return false; + + Min = m_vPoints[first].GetYMin(); + Max = m_vPoints[first].GetYMax(); + for (unsigned i=first; i Max) + Max = m_vPoints[i].GetYMax(); + } + return true; +} + +template +bool CChartSerieBase::GetVisiblePoints(unsigned& uFirst, unsigned& uLast) const +{ + if (m_vPoints.GetPointsCount() == 0) + return false; + + double Min=0, Max=0; + bool bResult = false; + switch (m_vPoints.GetOrdering()) + { + case poNoOrdering: + uFirst = 0; + uLast = GetPointsCount() - 1; + bResult = true; + break; + case poXOrdering: + m_pHorizontalAxis->GetMinMax(Min, Max); + bResult = m_vPoints.GetVisiblePoints(Min, Max, uFirst, uLast); + break; + case poYOrdering: + m_pVerticalAxis->GetMinMax(Min, Max); + bResult = m_vPoints.GetVisiblePoints(Min, Max, uFirst, uLast); + break; + } + + return bResult; +} + +template +CPoint CChartSerieBase::GetPointScreenCoord(unsigned uPointIndex) +{ + unsigned uCount = m_vPoints.GetPointsCount(); + ASSERT(uPointIndex +CChartBalloonLabel* CChartSerieBase::CreateBalloonLabel(unsigned uPointIndex, + const TChartString& strLabelText) +{ + ASSERT(uPointIndex* pToReturn = new CChartBalloonLabel(m_pParentCtrl, this); + pToReturn->SetLabelText(strLabelText); + AttachCustomLabel(uPointIndex, pToReturn); + return pToReturn; +} + +template +void CChartSerieBase::RegisterMouseListener(CChartSeriesMouseListener* pListener) +{ + m_pMouseListener = pListener; +} + +template +void CChartSerieBase::UnregisterMouseListener() +{ + m_pMouseListener = NULL; +} + +template +CChartBalloonLabel* CChartSerieBase::CreateBalloonLabel(unsigned uPointIndex, + CChartLabelProvider* pLabelProvider) +{ + ASSERT(uPointIndex* pToReturn = new CChartBalloonLabel(m_pParentCtrl, this); + pToReturn->SetLabelProvider(pLabelProvider); + AttachCustomLabel(uPointIndex, pToReturn); + return pToReturn; +} + +template +void CChartSerieBase::AttachCustomLabel(unsigned uPointIndex, CChartLabel* pLabel) +{ + ASSERT(uPointIndexsecond; + } + m_mapLabels[uPointIndex] = pLabel; +} + +template +void CChartSerieBase::DrawLabels(CDC* pDC) +{ + TLabelMap::iterator iter = m_mapLabels.begin(); + for (iter; iter!=m_mapLabels.end(); iter++) + { + iter->second->Draw(pDC,iter->first); + } +} + +template +bool CChartSerieBase::OnMouseEvent(CChartMouseListener::MouseEvent mouseEvent, + const CPoint& screenPoint) +{ + bool bHandled = false; + if (m_pMouseListener == NULL) + return bHandled; + + if ( (mouseEvent==CChartMouseListener::MouseMove) && + !NotifyMouseMoveEnabled()) + { + return bHandled; + } + if ( (mouseEvent!=CChartMouseListener::MouseMove) && + !NotifyMouseClickEnabled()) + { + return bHandled; + } + + unsigned uPtIndex = 0; + if (IsPointOnSerie(screenPoint,uPtIndex)) + { + m_pMouseListener->OnMouseEventSeries(mouseEvent,screenPoint,this,uPtIndex); + bHandled = true; + } + + return bHandled; +} diff --git a/ChartDemo/ChartCtrl/ChartSeriesMouseListener.h b/ChartDemo/ChartCtrl/ChartSeriesMouseListener.h new file mode 100644 index 0000000..658f86a --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartSeriesMouseListener.h @@ -0,0 +1,65 @@ +/* + * + * ChartSeriesMouseListener.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#ifndef _CHARTSERIESMOUSELISTENER_H_ +#define _CHARTSERIESMOUSELISTENER_H_ + +#include "ChartMouseListener.h" + +//#pragma warning( disable : 4100 ) + +template +class CChartSerieBase; + +//! Listener for mouse events occuring on a series. +/** + This is an interface which must be implemented in order to receive + mouse notifications. You can then register your class with the chart + control by calling RegisterMouseListener. +**/ +template +class CChartSeriesMouseListener +{ +public: + //! Constructor + CChartSeriesMouseListener() { } + //! Destructor + virtual ~CChartSeriesMouseListener() { } + + //! Virtual function to implement in order to be notified when a mouse event occurs on a series. + /** + @param mouseEvent + The mouse event which occured + @param point + The screen point on which the event occured + @param pSerie + The series on which the event occured + @param uPointIndex + The index of the point on which the event occured. In case the event + did not occur on a specific point but on the series itself (e.g. clicking + between two points on a line series), INVALID_POINT is passed for this + parameter. + **/ + virtual void OnMouseEventSeries(CChartMouseListener::MouseEvent mouseEvent, CPoint point, + CChartSerieBase* pSerie, unsigned uPointIndex) { } +}; + +#endif // _CHARTSERIESMOUSELISTENER_H_ \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartStandardAxis.cpp b/ChartDemo/ChartCtrl/ChartStandardAxis.cpp new file mode 100644 index 0000000..765b81a --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartStandardAxis.cpp @@ -0,0 +1,197 @@ +/* + * + * ChartAxis.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + */ + +#include "stdafx.h" +#include "ChartStandardAxis.h" +#include "ChartCtrl.h" +#include +#include +#include +#include + +using namespace std; + +CChartStandardAxis::CChartStandardAxis() + : CChartAxis(), m_dFirstTickValue(0), + m_dTickIncrement(1.0), m_uDecCount(0) +{ +} + +CChartStandardAxis::~CChartStandardAxis() +{ +} + + +void CChartStandardAxis::SetTickIncrement(bool bAuto, double newIncrement) +{ + m_bAutoTicks = bAuto; + if (!m_bAutoTicks) + { + m_dTickIncrement = newIncrement; + + int Zeros = (int)floor(log10(m_dTickIncrement)); + + int Digits = 0; + if (Zeros<0) + { + //We must set decimal places. In the other cases, Digits will be 0. + Digits = (int)fabs(Zeros*1.0); + } + SetDecimals(Digits); + } +} + +double CChartStandardAxis::GetFirstTickValue() const +{ + double dRetVal = m_dFirstTickValue; + if (m_bDiscrete) + { + dRetVal = m_dFirstTickValue - m_dTickIncrement; + } + return dRetVal; +} + +bool CChartStandardAxis::GetNextTickValue(double dCurrentTick, double& dNextTick) const +{ + if (m_dTickIncrement==0) + return false; + + dNextTick = dCurrentTick + m_dTickIncrement; + if (dNextTick <= m_MaxValue) + return true; + else + return false; +} + +long CChartStandardAxis::ValueToScreenDiscrete(double dValue) const +{ + // In discrete mode, all values between two ticks are "directed" + // to the middle of the interval. + double precision = 0.0000000001; + if (dValue < 0) + precision = -0.0000000001; + int tickNr = (int)((dValue+precision)/m_dTickIncrement); + dValue = tickNr * m_dTickIncrement; + + dValue += m_dTickIncrement/2.0; + return ValueToScreenStandard(dValue); +} + +long CChartStandardAxis::GetTickPos(double TickVal) const +{ + // The tick is always at the same position, + // even if the axis is discrete. + return ValueToScreenStandard(TickVal); +} + +TChartString CChartStandardAxis::GetTickLabel(double TickValue) const +{ + TChartStringStream ssLabel; + ssLabel << fixed << setprecision(m_uDecCount) << TickValue; + return ssLabel.str(); +} + +void CChartStandardAxis::RefreshTickIncrement() +{ + if (!m_bAutoTicks) + return; + + if (m_MaxValue == m_MinValue) + { + m_dTickIncrement = 0; + return; + } + + int PixelSpace; + if (m_bIsHorizontal) + PixelSpace = 30; + else + PixelSpace = 20; + + int MaxTickNumber = (int)fabs((m_EndPos-m_StartPos)/PixelSpace * 1.0); + + //Calculate the appropriate TickSpace (1 tick every 30 pixel +/-) + //Temporary tick increment + double TempTickIncrement = (m_MaxValue-m_MinValue)/MaxTickNumber; + + // Calculate appropriate tickSpace (not rounded on 'strange values' but + // on something like 1, 2 or 5*10^X where X is optimalized for showing the most + // significant digits) + int Zeros = (int)floor(log10(TempTickIncrement)); + double MinTickIncrement = pow(10.0,Zeros); + + int Digits = 0; + if (Zeros<0) + { + //We must set decimal places. In the other cases, Digits will be 0. + Digits = (int)fabs(Zeros*1.0); + } + + if (MinTickIncrement>=TempTickIncrement) + { + m_dTickIncrement = MinTickIncrement; + SetDecimals(Digits); + } + else if (MinTickIncrement*2>=TempTickIncrement) + { + m_dTickIncrement = MinTickIncrement*2; + SetDecimals(Digits); + } + else if (MinTickIncrement*5>=TempTickIncrement) + { + m_dTickIncrement = MinTickIncrement*5; + SetDecimals(Digits); + } + else if (MinTickIncrement*10>=TempTickIncrement) + { + m_dTickIncrement = MinTickIncrement*10; + if (Digits) + SetDecimals(Digits-1); + else + SetDecimals(Digits); + } +} + +void CChartStandardAxis::RefreshFirstTick() +{ + if (m_dTickIncrement!=0) + { + if (m_MinValue == 0) + m_dFirstTickValue = 0; + else if (m_MinValue>0) + { + m_dFirstTickValue = (int)(m_MinValue/m_dTickIncrement) * m_dTickIncrement; + while (m_dFirstTickValuem_MinValue) + m_dFirstTickValue -= m_dTickIncrement; + if (!(m_dFirstTickValue == m_MinValue)) + m_dFirstTickValue += m_dTickIncrement; + } + } + else // m_TickIncrement!=0 + { + m_dFirstTickValue = m_MinValue; + } +} diff --git a/ChartDemo/ChartCtrl/ChartStandardAxis.h b/ChartDemo/ChartCtrl/ChartStandardAxis.h new file mode 100644 index 0000000..2f9926d --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartStandardAxis.h @@ -0,0 +1,76 @@ +/* + * + * ChartStandardAxis.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#ifndef _CHARTSTANDARDAXIS_H_ +#define _CHARTSTANDARDAXIS_H_ + +#include "ChartAxis.h" + +//! Specialization of a CChartAxis class to display standard values. +class CChartStandardAxis : public CChartAxis +{ +friend CChartCtrl; + +public: + //! Sets the tick increment. + /** + The tick increment is the value between two adjacents + ticks on the axis. + @param bAuto + Specifies if the tick increment is automatically calculated. + @param newIncrement + The tick increment to use in manual mode. + **/ + void SetTickIncrement(bool bAuto, double newIncrement); + //! Gets the tick increment. + /** + The tick increment is the value between two adjacents + ticks on the axis. + **/ + double GetTickIncrement() const { return m_dTickIncrement; } + +private: + //! Default constructor + CChartStandardAxis(); + //! Default destructor + ~CChartStandardAxis(); + + double GetFirstTickValue() const; + bool GetNextTickValue(double dCurrentTick, double& dNextTick) const; + TChartString GetTickLabel(double TickValue) const; + long ValueToScreenDiscrete(double Value) const; + long GetTickPos(double TickVal) const; + + void RefreshTickIncrement(); + void RefreshFirstTick(); + + //! Sets the number of decimals points. + void SetDecimals(unsigned uDecimals) { m_uDecCount = uDecimals; } + + //! Caches the value of the first tick. + double m_dFirstTickValue; + //! Indicates the space between ticks (in axis value). + double m_dTickIncrement; + //! Number of decimals to display for tick labels. + unsigned int m_uDecCount; +}; + +#endif // _CHARTSTANDARDAXIS_H_ \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartString.h b/ChartDemo/ChartCtrl/ChartString.h new file mode 100644 index 0000000..7876266 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartString.h @@ -0,0 +1,33 @@ +/* + * + * ChartString.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#pragma once + +#include +#include + +#if defined _UNICODE || defined UNICODE + typedef std::wstring TChartString; + typedef std::wstringstream TChartStringStream; +#else + typedef std::string TChartString; + typedef std::stringstream TChartStringStream; +#endif \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartSurfaceSerie.cpp b/ChartDemo/ChartCtrl/ChartSurfaceSerie.cpp new file mode 100644 index 0000000..06cceeb --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartSurfaceSerie.cpp @@ -0,0 +1,289 @@ +/* + * + * ChartSurfaceSerie.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#include "stdafx.h" +#include "ChartSurfaceSerie.h" +#include "ChartCtrl.h" + + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CChartSurfaceSerie::CChartSurfaceSerie(CChartCtrl* pParent) + : CChartXYSerie(pParent), m_FillStyle(fsHatchDownDiag), m_bHorizontal(true) +{ + +} + +CChartSurfaceSerie::~CChartSurfaceSerie() +{ + +} + +void CChartSurfaceSerie::Draw(CDC* pDC) +{ + DrawAll(pDC); +} + +void CChartSurfaceSerie::DrawAll(CDC* pDC) +{ + unsigned uFirst=0, uLast=0; + if (!GetVisiblePoints(uFirst,uLast)) + return; + + if (uFirst>0) + uFirst--; + if (uLastSelectObject(&NewBrush); + + for (unsigned index=uFirst; index<=uLast; index++) + { + SChartXYPoint Point = GetPoint(index); + ValueToScreen(Point.X, Point.Y, pPoints[index-uFirst+1]); + } + + if (m_bHorizontal) + { + pPoints[0].x = pPoints[1].x; + pPoints[uCount+1].x = pPoints[uCount].x; + + double Position = m_pHorizontalAxis->GetPosition()/100.00; + int AxisPos = m_PlottingRect.top + (int)(Position * (m_PlottingRect.bottom-m_PlottingRect.top)); + + pPoints[0].y = AxisPos; + pPoints[uCount+1].y = AxisPos; + } + else + { + pPoints[0].y = pPoints[1].y; + pPoints[uCount+1].y = pPoints[uCount].y; + + double Position = m_pVerticalAxis->GetPosition()/100.00; + int AxisPos = m_PlottingRect.left + (int)(Position * (m_PlottingRect.right-m_PlottingRect.left)); + + pPoints[0].x = AxisPos; + pPoints[uCount+1].x = AxisPos; + } + + pDC->SetBkMode(TRANSPARENT); + //To have lines limited in the drawing rectangle : + CRect TempClipRect(m_PlottingRect); + TempClipRect.DeflateRect(1,1); + pDC->SetBkMode(TRANSPARENT); + pDC->IntersectClipRect(TempClipRect); + + pDC->Polygon(pPoints,uCount+2); + pDC->SelectClipRgn(NULL); + pDC->SelectObject(pOldBrush); + DeleteObject(NewBrush); + + delete[] pPoints; +} + +void CChartSurfaceSerie::DrawLegend(CDC* pDC, const CRect& rectBitmap) const +{ + if (m_strSerieName== _T("")) + return; + + // Draw the bitmap + CBrush NewBrush; + if (m_FillStyle == fsSolid) + NewBrush.CreateSolidBrush(m_SerieColor); + else + { + int nIndex = 0; + switch (m_FillStyle) + { + case fsHatchDownDiag: + nIndex = HS_FDIAGONAL; + break; + case fsHatchUpDiag: + nIndex = HS_BDIAGONAL; + break; + case fsHatchCross: + nIndex = HS_CROSS; + break; + case fsHatchDiagCross: + nIndex = HS_DIAGCROSS; + break; + case fsHatchHorizontal: + nIndex = HS_HORIZONTAL; + break; + case fsHatchVertical: + nIndex = HS_VERTICAL; + break; + } + NewBrush.CreateHatchBrush(nIndex,m_SerieColor); + } + + CBrush* pOldBrush = pDC->SelectObject(&NewBrush); + + pDC->Rectangle(rectBitmap); + + pDC->SelectObject(pOldBrush); + DeleteObject(NewBrush); +} + +void CChartSurfaceSerie::SetFillStyle(FillStyle NewStyle) +{ + m_FillStyle = NewStyle; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartSurfaceSerie::SetHorizontal(bool bHoriz) +{ + m_bHorizontal = bHoriz; + if (m_bHorizontal) + m_vPoints.SetOrdering(poXOrdering); + else + m_vPoints.SetOrdering(poYOrdering); + m_pParentCtrl->RefreshCtrl(); +} + +void CChartSurfaceSerie::SetSeriesOrdering(PointsOrdering ) +{ + TRACE("Can't change the series ordering of a surface series."); +} + +bool CChartSurfaceSerie::IsPointOnSerie(const CPoint& screenPoint, + unsigned& uIndex) const +{ + uIndex = INVALID_POINT; + if (!m_bIsVisible) + return false; + + unsigned uFirst=0, uLast=0; + if (!GetVisiblePoints(uFirst,uLast)) + return false; + + if (uFirst>0) + uFirst--; + if (uLast point2.x)) + continue; + + int Position = m_pHorizontalAxis->GetPosition(); + if ( (Position==100) && (screenPoint.y > (screenPoint.x *lineSlope + lineOffset)) ) + bResult = true; + if ( (Position==0) && (screenPoint.y < (screenPoint.x *lineSlope + lineOffset)) ) + bResult = true; + + if (bResult) + { + // Check if the click is close to one of the two points. + int xDist = abs(screenPoint.x - point1.x); + int yDist = abs(screenPoint.y - point1.y); + if (xDist<=5 && yDist<=5) + uIndex = ptIndex; + xDist = abs(screenPoint.x - point2.x); + yDist = abs(screenPoint.y - point2.y); + if (xDist<=5 && yDist<=5) + uIndex = ptIndex+1; + break; + } + } + else + { + if ( (screenPoint.y > point1.y) || (screenPoint.y < point2.y)) + continue; + + int Position = m_pVerticalAxis->GetPosition(); + if ( (Position==0) && (screenPoint.x < (screenPoint.y-lineOffset)/lineSlope) ) + bResult = true; + if ( (Position==100) && (screenPoint.x > (screenPoint.y-lineOffset)/lineSlope) ) + bResult = true; + + if (bResult) + { + // Check if the click is close to one of the two points. + int xDist = abs(screenPoint.x - point1.x); + int yDist = abs(screenPoint.y - point1.y); + if (xDist<=5 && yDist<=5) + uIndex = ptIndex; + xDist = abs(screenPoint.x - point2.x); + yDist = abs(screenPoint.y - point2.y); + if (xDist<=5 && yDist<=5) + uIndex = ptIndex+1; + break; + } + } + } + + return bResult; +} diff --git a/ChartDemo/ChartCtrl/ChartSurfaceSerie.h b/ChartDemo/ChartCtrl/ChartSurfaceSerie.h new file mode 100644 index 0000000..c0090c7 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartSurfaceSerie.h @@ -0,0 +1,128 @@ +/* + * + * ChartSurfaceSerie.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#if !defined(AFX_CHARTSURFACESERIE_H__28A77823_43BD_4502_9AA7_A2B227454035__INCLUDED_) +#define AFX_CHARTSURFACESERIE_H__28A77823_43BD_4502_9AA7_A2B227454035__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "ChartXYSerie.h" + +//! Specialization of a CChartSerie to display a surface series. +/** + A surface can be horizontal (default) or vertical: this defines how + the filling of the surface is done. For a horizontal surface, the + filling is done between the points and the associated horizontal axis + and for a vertical surface, the filling is done between the points + and the associated vertical axis. + The series can be associated with a secondary axis. For example, if + the surface series is horizontal and is associated with the top axis + (secondary axis), the filling is done between the top axis and the points. +**/ +class CChartSurfaceSerie : public CChartXYSerie +{ +public: + //! Constructor + CChartSurfaceSerie(CChartCtrl* pParent); + //! Destructor + virtual ~CChartSurfaceSerie(); + + //! The different fill styles + enum FillStyle + { + fsSolid = 0, + fsHatchDownDiag, + fsHatchUpDiag, + fsHatchCross, + fsHatchDiagCross, + fsHatchHorizontal, + fsHatchVertical + }; + + //! Sets the fill style + void SetFillStyle(FillStyle NewStyle); + //! Returns the fill style + FillStyle GetFillStyle() const { return m_FillStyle; } + + //! Sets the series in horizontal or vertical mode + /** + If the series is in horizontal mode, the filling will be done between + the data points and the horizontal axis. + **/ + void SetHorizontal(bool bHoriz); + //! Returns true if the series is in horizontal mode + bool GetHorizontal() const { return m_bHorizontal; } + + //! Check whether a screen point is on the series. + /** + This function returns true if the screen point is on the surface. + If the screen point is also close to a specific point of the series, the + index of the point is stored in the uIndex parameter. Otherwise, this + parameter contains INVALID_POINT. + @param screenPoint + The screen point to test + @param uIndex + If the point is close to a specific point of the series, its index is stored here. + @return true if the point is on the series + **/ + bool IsPointOnSerie(const CPoint& screenPoint, unsigned& uIndex) const; + + void CChartSurfaceSerie::SetSeriesOrdering(PointsOrdering ); +private: + //! Override in order to avoid changing series ordering. +// void SetSeriesOrdering(CChartPointsArray::PointsOrdering); + + //! Draws the legend icon for the series. + /** + This pure virtual function should be overriden by child classes. + @param pDC + The device context used to draw + @param rectBitmap + The rectangle in which to draw the legend icon + **/ + void DrawLegend(CDC* pDC, const CRect& rectBitmap) const; + + //! Draws the most recent points of the series. + /** + This pure virtual function should be overriden by child classes. + This function should only draw the points that were not previously + drawn. + @param pDC + The device context used to draw + **/ + void Draw(CDC* pDC); + //! Redraws the full series. + /** + This pure virtual function should be overriden by child classes. + @param pDC + The device context used to draw + **/ + void DrawAll(CDC *pDC); + + //! The brush style used to fill the surface + FillStyle m_FillStyle; + //! The horizontal/vertical mode + bool m_bHorizontal; +}; + +#endif // !defined(AFX_CHARTSURFACESERIE_H__28A77823_43BD_4502_9AA7_A2B227454035__INCLUDED_) diff --git a/ChartDemo/ChartCtrl/ChartTitle.cpp b/ChartDemo/ChartCtrl/ChartTitle.cpp new file mode 100644 index 0000000..43774ec --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartTitle.cpp @@ -0,0 +1,201 @@ +/* + * + * ChartTitle.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#include "stdafx.h" +#include "ChartTitle.h" +#include "ChartCtrl.h" +#include "Math.h" + +using namespace std; + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CChartTitle::CChartTitle(CChartCtrl* pParent) +{ + m_pParentCtrl = pParent; + m_bIsVisible = true; + m_TextColor = RGB(0,0,0); +} + +CChartTitle::~CChartTitle() +{ + +} + +void CChartTitle::SetFont(int iPointSize, const TChartString& strFaceName) +{ + m_DefaultFont.SetFont(strFaceName, iPointSize); + m_pParentCtrl->RefreshCtrl(); +} + +void CChartTitle::SetFont(const CChartFont& newFont) +{ + m_DefaultFont = newFont; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartTitle::SetColor(COLORREF NewColor) +{ + m_TextColor = NewColor; + m_pParentCtrl->RefreshCtrl(); +} + +void CChartTitle::SetLineFont(int iLineIndex, + int iPointSize, + const TChartString& strFaceName) +{ + CChartFont newFont(strFaceName,iPointSize); + m_mapLineFonts[iLineIndex] = newFont; +} + +void CChartTitle::SetLineFont(int iLineIndex, const CChartFont& newFont) +{ + m_mapLineFonts[iLineIndex] = newFont; +} + +void CChartTitle::AddString(const TChartString& NewString) +{ + m_StringArray.push_back(NewString); + m_pParentCtrl->RefreshCtrl(); +} + +size_t CChartTitle::GetStringCount() const +{ + return m_StringArray.size(); +} + +TChartString CChartTitle::GetString(size_t Index) const +{ + if ( (Index<0) || (Index>=m_StringArray.size()) ) + return _T(""); + return m_StringArray[Index]; +} + +void CChartTitle::RemoveAll() +{ + m_StringArray.clear(); + m_pParentCtrl->RefreshCtrl(); +} + +void CChartTitle::Draw(CDC *pDC) +{ + if (!pDC->GetSafeHdc()) + return; + if (!m_bIsVisible) + return; + + m_DefaultFont.SelectFont(pDC); + COLORREF OldColor = pDC->SetTextColor(m_TextColor); + int iPrevMode = pDC->SetBkMode(TRANSPARENT); + + //Draw all entries + int YPos = 4; + size_t TitleCount = m_StringArray.size(); + for (size_t i=0;i::iterator iter = m_mapLineFonts.find(i); + if (iter != m_mapLineFonts.end()) + iter->second.SelectFont(pDC); + + //Draw Text + int TextWidth = pDC->GetTextExtent(m_StringArray[i].c_str()).cx; + int TextHeigh = pDC->GetTextExtent(m_StringArray[i].c_str()).cy; + + int XPos = m_TitleRect.left + (int)fabs((m_TitleRect.left-m_TitleRect.right)/2.0) - TextWidth/2; + +/* if (m_bShadow) + { + pDC->SetTextColor(m_ShadowColor); + pDC->ExtTextOut(XPos+m_iShadowDepth,m_TitleRect.top+YPos+m_iShadowDepth, + ETO_CLIPPED,NULL,m_StringArray[i].c_str(),NULL); + pDC->SetTextColor(m_TextColor); + }*/ + pDC->ExtTextOut(XPos,m_TitleRect.top+YPos,ETO_CLIPPED,NULL,m_StringArray[i].c_str(),NULL); + + if (iter != m_mapLineFonts.end()) + iter->second.UnselectFont(pDC); + + YPos += TextHeigh + 2; + } + + m_DefaultFont.UnselectFont(pDC); + pDC->SetTextColor(OldColor); + pDC->SetBkMode(iPrevMode); +} + +CSize CChartTitle::GetSize(CDC *pDC) +{ + CSize TitleSize; + + if (!m_bIsVisible) + { + TitleSize.cx = TitleSize.cy = 0; + return TitleSize; + } + + int Height = 4; //Upper space + CSize TextSize = 0; + int MaxTextWidth = 0; + + size_t TitleCount = m_StringArray.size(); + if (TitleCount==0) + { + TitleSize.cx = TitleSize.cy = 0; + return TitleSize; + } + + m_DefaultFont.SelectFont(pDC); + for (size_t i=0;i::iterator iter = m_mapLineFonts.find(i); + if (iter != m_mapLineFonts.end()) + iter->second.SelectFont(pDC); + + TextSize = pDC->GetTextExtent(m_StringArray[i].c_str()); + Height += TextSize.cy + 2; + if (TextSize.cx > MaxTextWidth) + MaxTextWidth = TextSize.cx; + + if (iter != m_mapLineFonts.end()) + iter->second.UnselectFont(pDC); + } + + TitleSize.cx = MaxTextWidth + 2; + TitleSize.cy = Height; + + m_TitleRect.bottom = m_TitleRect.top + Height; + + m_DefaultFont.UnselectFont(pDC); + return TitleSize; +} + +BOOL CChartTitle::IsPointInside(const CPoint& screenPoint) const +{ + return m_TitleRect.PtInRect(screenPoint); +} diff --git a/ChartDemo/ChartCtrl/ChartTitle.h b/ChartDemo/ChartCtrl/ChartTitle.h new file mode 100644 index 0000000..29c2849 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartTitle.h @@ -0,0 +1,136 @@ +/* + * + * ChartTitle.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#if !defined(AFX_CHARTTITLE_H__49972787_6D28_4F81_A12F_420947456913__INCLUDED_) +#define AFX_CHARTTITLE_H__49972787_6D28_4F81_A12F_420947456913__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include +#include +#include "ChartString.h" +#include "ChartFont.h" + +class CChartCtrl; + +//! This class is responsible for the titles displayed on the control. +/** + Several lines can be displayed in the title, each one possibly with + its own font. It is retrieved by calling the GetTitle() function + from the CChartCtrl class. +**/ +class CChartTitle +{ + friend CChartCtrl; + +public: + //! Returns the number of lines in the title. + size_t GetStringCount() const; + //! Returns a specific line, specified by its index. + TChartString GetString(size_t Index) const; + //! Adds a new line to the title. + void AddString(const TChartString& NewString); + //! Removes all the lines displayed in the title. + void RemoveAll(); + + //! Sets the default font. + /** + @param iPointSize + The font point size. + @param strFaceName + The font face name ("Times New Roman", "Arial", ...) + **/ + void SetFont(int iPointSize, const TChartString& strFaceName); + //! Sets the default font. + /** + This function allows to set extended font style by passing + a CChartFont object. + @param newFont + The new font. + **/ + void SetFont(const CChartFont& newFont); + //! Sets the font for a specific line. + /** + @param iLineIndex + The index of the line to set the font. + @param iPointSize + The font point size. + @param strFaceName + The font face name ("Times New Roman", "Arial", ...) + **/ + void SetLineFont(int iLineIndex, int iPointSize, const TChartString& strFaceName); + //! Sets the font for a specific line. + /** + This function allows to set extended font style by passing + a CChartFont object. + @param iLineIndex + The index of the line to set the font. + @param newFont + The new font. + **/ + void SetLineFont(int iLineIndex, const CChartFont& newFont); + + //! Shows/hides the title. + void SetVisible(bool bVisible) { m_bIsVisible = bVisible; } + //! Returns true if the title is visible. + bool IsVisible() const { return m_bIsVisible; } + + //! Returns the text color. + COLORREF GetColor() const { return m_TextColor; } + //! Sets the text color. + void SetColor(COLORREF NewColor); + + //! Returns true if a screen point is in the region of the title. + BOOL IsPointInside(const CPoint& screenPoint) const; + +private: + //! Constructor + CChartTitle(CChartCtrl* pParent); + //! Destructor + virtual ~CChartTitle(); + + //! Sets the rectangle in which to display the title. + void SetTitleRect(const CRect& newRect) { m_TitleRect = newRect; } + //! Returns the size of the title lines. + CSize GetSize(CDC* pDC); + //! Draw the title. + void Draw(CDC *pDC); + + //! The parent charting control. + CChartCtrl* m_pParentCtrl; + //! Vector containing all strings to display. + std::vector m_StringArray; + //! Map containing all the fonts used for the title lines. + std::map m_mapLineFonts; + + //! Specifies if the title is visible. + bool m_bIsVisible; + //! The default font used to draw the titles. + CChartFont m_DefaultFont; + //! The text color. + COLORREF m_TextColor; + //! The rectangle in which to draw the titles. + CRect m_TitleRect; +}; + +#endif // !defined(AFX_CHARTTITLE_H__49972787_6D28_4F81_A12F_420947456913__INCLUDED_) diff --git a/ChartDemo/ChartCtrl/ChartXYSerie.cpp b/ChartDemo/ChartCtrl/ChartXYSerie.cpp new file mode 100644 index 0000000..3f4eaa1 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartXYSerie.cpp @@ -0,0 +1,186 @@ +/* + * + * ChartXYSerie.cpp + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#include "stdafx.h" +#include "ChartXYSerie.h" + +CChartXYSerie::CChartXYSerie(CChartCtrl* pParent) + : CChartSerieBase(pParent) +{ +} + +CChartXYSerie::~CChartXYSerie() +{ +} + +void CChartXYSerie::AddPoint(double X, double Y) +{ + SChartXYPoint newPoint(X, Y); + CChartSerieBase::AddPoint(newPoint); +} + +void CChartXYSerie::AddPoints(double* pX, double* pY, unsigned Count) +{ + SChartXYPoint* pPoints = new SChartXYPoint[Count]; + for (unsigned i=0; i::AddPoints(pPoints, Count); + delete pPoints; +} + +void CChartXYSerie::SetPoints(double* pX, double* pY, unsigned Count) +{ + SChartXYPoint* pPoints = new SChartXYPoint[Count]; + for (unsigned i=0; i::SetPoints(pPoints, Count); + delete pPoints; +} + +double CChartXYSerie::GetXPointValue(unsigned PointIndex) const +{ + return m_vPoints[PointIndex].GetX(); +} + +double CChartXYSerie::GetYPointValue(unsigned PointIndex) const +{ + return m_vPoints[PointIndex].GetY(); +} + +void CChartXYSerie::SetXPointValue(unsigned PointIndex, double NewVal) +{ + m_vPoints[PointIndex].X = NewVal; + m_vPoints.ReorderPoints(); + + RefreshAutoAxes(true); +} + +void CChartXYSerie::SetYPointValue(unsigned PointIndex, double NewVal) +{ + m_vPoints[PointIndex].Y = NewVal; + m_vPoints.ReorderPoints(); + + RefreshAutoAxes(true); +} + +#ifndef NO_USER_DATA +void CChartXYSerie::SetUserData(unsigned uPointIndex, void* pData) +{ + m_vPoints[uPointIndex].pUserData = pData; +} + +void* CChartXYSerie::GetUserData(unsigned uPointIndex) +{ + return m_vPoints[uPointIndex].pUserData; +} +#endif + +void CChartXYSerie::GetBezierControlPoints(unsigned uFirst, + unsigned uLast, + SChartXYPoint* &pKnots, + SChartXYPoint* &pFirstControlPoints, + SChartXYPoint* &pSecondControlPoints) const +{ + int Count = uLast - uFirst - 1; + if (Count < 1) + { + pFirstControlPoints = new SChartXYPoint[0]; + pSecondControlPoints = new SChartXYPoint[0]; + pKnots = new SChartXYPoint[0]; + return; + } + + pKnots = new SChartXYPoint[uLast-uFirst]; + SChartXYPoint* pPoints = m_vPoints.GetInternalBuffer(); + memcpy(pKnots, pPoints+uFirst, (uLast-uFirst)*sizeof(SChartXYPoint)); + + // Calculate first Bezier control points + // Right hand side vector + double* rhs = new double[Count]; + + // Set right hand side X values + int i=0; + for (i = 1; i < Count - 1; ++i) + rhs[i] = 4 * pKnots[i].X + 2 * pKnots[i + 1].X; + rhs[0] = pKnots[0].X + 2 * pKnots[1].X; + rhs[Count - 1] = 3 * pKnots[Count - 1].X; + // Get first control points X-values + double* pFirstX = GetFirstControlPoints(rhs, Count); + + // Set right hand side Y values + for (i = 1; i < Count - 1; ++i) + rhs[i] = 4 * pKnots[i].Y + 2 * pKnots[i + 1].Y; + rhs[0] = pKnots[0].Y + 2 * pKnots[1].Y; + rhs[Count - 1] = 3 * pKnots[Count - 1].Y; + // Get first control points Y-values + double* pFirstY = GetFirstControlPoints(rhs, Count); + + // Fill output arrays. + pFirstControlPoints = new SChartXYPoint[Count]; + pSecondControlPoints = new SChartXYPoint[Count]; + for (i = 0; i < Count; ++i) + { + // First control point + pFirstControlPoints[i].X = pFirstX[i]; + pFirstControlPoints[i].Y = pFirstY[i]; + // Second control point + if (i < Count - 1) + { + pSecondControlPoints[i].X = 2 * pKnots[i + 1].X - pFirstX[i + 1]; + pSecondControlPoints[i].Y = 2 * pKnots[i + 1].Y - pFirstY[i + 1]; + } + else + { + pSecondControlPoints[i].X = (pKnots[Count].X + pFirstX[Count - 1]) / 2; + pSecondControlPoints[i].Y = (pKnots[Count].Y + pFirstY[Count - 1]) / 2; + } + } + + delete[] rhs; + delete[] pFirstX; + delete[] pFirstY; +} + +double* CChartXYSerie::GetFirstControlPoints(double* rhs, int Count) const +{ + double* pPoints = new double[Count]; // Solution vector. + double* pTemp = new double[Count]; // Temp workspace. + + double b = 2.0; + pPoints[0] = rhs[0] / b; + int i =0; + for (i = 1; i < Count; i++) // Decomposition and forward substitution. + { + pTemp[i] = 1 / b; + b = (i < Count - 1 ? 4.0 : 2.0) - pTemp[i]; + pPoints[i] = (rhs[i] - pPoints[i - 1]) / b; + } + for (i = 1; i < Count; i++) + pPoints[Count - i - 1] -= pTemp[Count - i] * pPoints[Count - i]; // Backsubstitution. + delete[] pTemp; + return pPoints; +} \ No newline at end of file diff --git a/ChartDemo/ChartCtrl/ChartXYSerie.h b/ChartDemo/ChartCtrl/ChartXYSerie.h new file mode 100644 index 0000000..97af801 --- /dev/null +++ b/ChartDemo/ChartCtrl/ChartXYSerie.h @@ -0,0 +1,157 @@ +/* + * + * ChartXYSerie.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#pragma once +#include "ChartSerieBase.h" + +//! Structure containing a point data with X and Y values +struct SChartXYPoint +{ + SChartXYPoint() : X(0.0), Y(0.0) + { + #ifndef NO_USER_DATA + pUserData = NULL; + #endif + } + SChartXYPoint(double XVal, double YVal) : X(XVal), Y(YVal) + { + #ifndef NO_USER_DATA + pUserData = NULL; + #endif + } + + double GetX() const { return X; } + double GetY() const { return Y; } + double GetXMin() const { return X; } + double GetXMax() const { return X; } + double GetYMin() const { return Y; } + double GetYMax() const { return Y; } + + //! The point X value. + double X; + //! The point Y value. + double Y; + #ifndef NO_USER_DATA + //! Optional user data. + void *pUserData; + #endif +}; + +//! Specialization of a CChartSerieBase for series having data with an X and an Y value. +/** + This class is abstract and has to be implemented for specific series. It + already provides features which are common to all series with points having + an X and an Y value. Examples of such series are: point series, line series, + surface series and bar series. +**/ +class CChartXYSerie : public CChartSerieBase +{ +public: + //! Constructor + CChartXYSerie(CChartCtrl* pParent); + //! Destructor + virtual ~CChartXYSerie(); + + //! Adds a single data point to the series. + void AddPoint(double X, double Y); + //! Adds an array of points to the series. + /** + Points which were already present in the series are kept. + @param pX + Array of X values for the points + @param pY + Array of Y values for the points + @param Count + Size of each of both arrays (number of points to add) + **/ + void AddPoints(double* pX, double* pY, unsigned Count); + //! Sets an array of points to the series. + /** + Points which were already present in the series are discarded. + @param pX + Array of X values for the points + @param pY + Array of Y values for the points + @param Count + Size of each of both arrays (number of points to add) + **/ + void SetPoints(double* pX, double* pY, unsigned Count); + + //! Returns the Y value of a specific point in the series. + double GetYPointValue(unsigned PointIndex) const; + //! Returns the X value of a specific point in the series. + double GetXPointValue(unsigned PointIndex) const; + //! Sets the Y value of a specific point in the series. + /** + The control is refreshed to display the change. + @param PointIndex + The index of the points to change the Y value + @param NewVal + The new Y value of the point + **/ + void SetYPointValue(unsigned PointIndex, double NewVal); + //! Sets the X value of a specific point in the series. + /** + The control is refreshed to display the change. + @param PointIndex + The index of the points to change the Y value + @param NewVal + The new X value of the point + **/ + void SetXPointValue(unsigned PointIndex, double NewVal); + +#ifndef NO_USER_DATA + //! Sets user data for a specific point. + /** + User data can be disabled by adding the flag NO_USER_DATA in the preprocessor + definitions. This is usefull when you don't want to have an additional pointer + stored for each points in your series. + **/ + void SetUserData(unsigned uPointIndex, void* pData); + //! Retrieves user data for a specific point. + /** + User data can be disabled by adding the flag NO_USER_DATA in the preprocessor + definitions. This is usefull when you don't want to have an additional pointer + stored for each points in your series. + **/ + void* GetUserData(unsigned uPointIndex); +#endif + +protected: + //! Retrieves the control points of a bezier curve fitting the points stored in the array. + /** + @param uFirst + The index of the first point of the bezier curve + @param uLast + The index of the last point of the bezier curve + @param pKnots + This parameter will store the points data + @param pFirstControlPoints + This parameter will store the primary control points of the bezier curve + @param pSecondControlPoints + This parameter will store the secondary control points of the bezier curve + **/ + void GetBezierControlPoints(unsigned uFirst, unsigned uLast, SChartXYPoint* &pKnots, + SChartXYPoint* &pFirstControlPoints, SChartXYPoint* &pSecondControlPoints) const; + +private: + double* GetFirstControlPoints(double* rhs, int Count) const; +}; diff --git a/ChartDemo/ChartCtrl/PointsOrdering.h b/ChartDemo/ChartCtrl/PointsOrdering.h new file mode 100644 index 0000000..df6ee4c --- /dev/null +++ b/ChartDemo/ChartCtrl/PointsOrdering.h @@ -0,0 +1,33 @@ +/* + * + * PointOrdering.h + * + * Written by Cédric Moonen (cedric_moonen@hotmail.com) + * + * + * + * This code may be used for any non-commercial and commercial purposes in a compiled form. + * The code may be redistributed as long as it remains unmodified and providing that the + * author name and this disclaimer remain intact. The sources can be modified WITH the author + * consent only. + * + * This code is provided without any garanties. I cannot be held responsible for the damage or + * the loss of time it causes. Use it at your own risks + * + * An e-mail to notify me that you are using this code is appreciated also. + * + * + */ + +#pragma once + +//! Enumeration listing the types of ordering. +enum PointsOrdering +{ + //! The points are not ordered + poNoOrdering, + //! The points are ordered by their X values + poXOrdering, + //! The points are ordered by their Y values + poYOrdering +}; diff --git a/ChartDemo/ChartDemo.cpp b/ChartDemo/ChartDemo.cpp new file mode 100644 index 0000000..322e4f3 --- /dev/null +++ b/ChartDemo/ChartDemo.cpp @@ -0,0 +1,76 @@ +// ChartDemo.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "ChartDemo.h" +#include "ChartDemoDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CChartDemoApp + +BEGIN_MESSAGE_MAP(CChartDemoApp, CWinApp) + //{{AFX_MSG_MAP(CChartDemoApp) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CChartDemoApp construction + +CChartDemoApp::CChartDemoApp() +{ + // Place all significant initialization in InitInstance +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CChartDemoApp object + +CChartDemoApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CChartDemoApp initialization + +BOOL CChartDemoApp::InitInstance() +{ + AfxEnableControlContainer(); + + // Standard initialization + // If you are not using these features and wish to reduce the size + // of your final executable, you should remove from the following + // the specific initialization routines you do not need. + +#if _MFC_VER < 0x0700 + #ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL + #else + Enable3dControlsStatic(); // Call this when linking to MFC statically + #endif +#else + InitCommonControls(); + CWinApp::InitInstance(); +#endif + + CChartDemoDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + + } + else if (nResponse == IDCANCEL) + { + + } + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/ChartDemo/ChartDemo.dsp b/ChartDemo/ChartDemo.dsp new file mode 100644 index 0000000..2aeb5ee --- /dev/null +++ b/ChartDemo/ChartDemo.dsp @@ -0,0 +1,440 @@ +# Microsoft Developer Studio Project File - Name="ChartDemo" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=ChartDemo - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ChartDemo.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ChartDemo.mak" CFG="ChartDemo - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ChartDemo - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "ChartDemo - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ChartDemo - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "ChartCtrl" /I "ColourPicker" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /Yu"stdafx.h" /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x40c /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x40c /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "ChartDemo - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "ChartCtrl" /I "ColourPicker" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FR /Yu"stdafx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x40c /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x40c /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "ChartDemo - Win32 Release" +# Name "ChartDemo - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\ChartDemo.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartDemoDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartSurfaceSerie.h +# End Source File +# Begin Source File + +SOURCE=.\LinePropDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\LinePropDialog.h +# End Source File +# Begin Source File + +SOURCE=.\PointsPropDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\PointsPropDialog.h +# End Source File +# Begin Source File + +SOURCE=.\SeriesPropDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\SurfacePropDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\SurfacePropDialog.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "rc2;rct;bin" +# Begin Group "Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\ChartDemo.ico +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ChartDemo.rc +# End Source File +# Begin Source File + +SOURCE=.\res\ChartDemo.rc2 +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\ChartDemo.h +# End Source File +# Begin Source File + +SOURCE=.\ChartDemoDlg.h +# End Source File +# Begin Source File + +SOURCE=.\SeriesPropDlg.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "ChartCtrl" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\ChartCtrl\ChartAxis.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartAxis.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartAxisLabel.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartAxisLabel.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartBalloonLabel.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartBalloonLabel.inl +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartBarSerie.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartBarSerie.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartCandlestickSerie.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartCandlestickSerie.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartCrossHairCursor.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartCrossHairCursor.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartCtrl.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartCtrl.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartCursor.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartCursor.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartDateTimeAxis.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartDateTimeAxis.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartDragLineCursor.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartDragLineCursor.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartFont.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartFont.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartGanttSerie.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartGanttSerie.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartGradient.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartGradient.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartGrid.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartGrid.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartLabel.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartLabel.inl +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartLegend.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartLegend.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartLineSerie.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartLineSerie.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartLogarithmicAxis.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartLogarithmicAxis.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartMouseListener.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartPointsArray.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartPointsArray.inl +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartPointsSerie.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartPointsSerie.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartScrollBar.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartScrollBar.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartSerie.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartSerie.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartSerieBase.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartSerieBase.inl +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartSeriesMouseListener.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartStandardAxis.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartStandardAxis.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartString.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartSurfaceSerie.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartSurfaceSerie.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartTitle.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartTitle.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartXYSerie.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\ChartXYSerie.h +# End Source File +# Begin Source File + +SOURCE=.\ChartCtrl\PointsOrdering.h +# End Source File +# End Group +# Begin Group "ColourCtrl" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\ColourPicker\ColourPicker.cpp +# End Source File +# Begin Source File + +SOURCE=.\ColourPicker\ColourPicker.h +# End Source File +# Begin Source File + +SOURCE=.\ColourPicker\ColourPopup.cpp +# End Source File +# Begin Source File + +SOURCE=.\ColourPicker\ColourPopup.h +# End Source File +# End Group +# End Target +# End Project diff --git a/ChartDemo/ChartDemo.dsw b/ChartDemo/ChartDemo.dsw new file mode 100644 index 0000000..a9346e3 --- /dev/null +++ b/ChartDemo/ChartDemo.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ChartDemo"=".\ChartDemo.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/ChartDemo/ChartDemo.h b/ChartDemo/ChartDemo.h new file mode 100644 index 0000000..1e85e06 --- /dev/null +++ b/ChartDemo/ChartDemo.h @@ -0,0 +1,49 @@ +// ChartDemo.h : main header file for the CHARTDEMO application +// + +#if !defined(AFX_CHARTDEMO_H__B7735086_C0AE_4EB2_91AF_2AA128DA4EBD__INCLUDED_) +#define AFX_CHARTDEMO_H__B7735086_C0AE_4EB2_91AF_2AA128DA4EBD__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CChartDemoApp: +// See ChartDemo.cpp for the implementation of this class +// + +class CChartDemoApp : public CWinApp +{ +public: + CChartDemoApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CChartDemoApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CChartDemoApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_CHARTDEMO_H__B7735086_C0AE_4EB2_91AF_2AA128DA4EBD__INCLUDED_) diff --git a/ChartDemo/ChartDemo.rc b/ChartDemo/ChartDemo.rc new file mode 100644 index 0000000..504d47b --- /dev/null +++ b/ChartDemo/ChartDemo.rc @@ -0,0 +1,454 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Chinese (P.R.C.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOG DISCARDABLE 0, 0, 235, 55 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "A propos de ChartDemo" +FONT 8, "MS Sans Serif" +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "ChartDemo version 1.0",IDC_STATIC,40,10,119,8, + SS_NOPREFIX + LTEXT "Copyright (C) 2006",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "OK",IDOK,178,7,50,14,WS_GROUP +END + +IDD_CHARTDEMO_DIALOG DIALOGEX 0, 0, 449, 543 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "ChartDemo" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "",IDC_CHARTCTRL,"ChartCtrl",WS_CLIPCHILDREN | + WS_TABSTOP,7,7,432,369 + GROUPBOX "Series",IDC_SERIES_GROUP,7,380,101,148 + LISTBOX IDC_SERIES_LIST,17,394,74,98,LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Add",IDC_ADDSERIES,17,500,37,14 + PUSHBUTTON "Delete",IDC_DELETESERIES,55,500,37,14 + GROUPBOX "General",IDC_GENERAL_GROUP,115,380,132,148 + LTEXT "Bkgnd color:",IDC_STATIC,123,397,41,8 + PUSHBUTTON "",IDC_BKGND_COLBTN,173,395,30,12 + CONTROL "Legend visible",IDC_LEGENDVIS_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,123,420,74,10 + LTEXT "Title:",IDC_STATIC,155,463,27,8 + EDITTEXT IDC_TITLE_EDIT,124,475,83,39,ES_CENTER | ES_MULTILINE | + ES_AUTOHSCROLL | ES_WANTRETURN + GROUPBOX "Axis",IDC_AXIS_GROUP,262,380,180,148 + CONTROL "Left",IDC_LEFTAXIS_RADIO,"Button",BS_AUTORADIOBUTTON, + 269,390,28,10 + CONTROL "Bottom",IDC_BOTTOMAXIS_RADIO,"Button", + BS_AUTORADIOBUTTON,308,390,38,10 + CONTROL "Right",IDC_RIGHTAXIS_RADIO,"Button",BS_AUTORADIOBUTTON, + 357,390,33,10 + CONTROL "Top",IDC_TOPAXIS_RADIO,"Button",BS_AUTORADIOBUTTON,401, + 390,29,10 + CONTROL "Visible",IDC_AXISVISIBLE_CHECK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,269,421,36,10 + CONTROL "Inverted",IDC_AXISINVERTED_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,320,421,50,10 + CONTROL "Automatic",IDC_AXISAUTOMATIC_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,377,421,53,10 + CONTROL "Grid",IDC_AXISGRIDVIS_CHECK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,269,441,29,10 + LTEXT "Axis min value:",IDC_AXISMINVAL_STATIC,280,462,63,8 + EDITTEXT IDC_AXISMINVAL_EDIT,355,460,40,14,ES_AUTOHSCROLL + LTEXT "Axis max value:",IDC_AXISMAXVAL_STATIC,278,481,63,8 + EDITTEXT IDC_AXISMAXVAL_EDIT,355,478,40,14,ES_AUTOHSCROLL + LTEXT "Label:",IDC_STATIC,286,502,25,8 + EDITTEXT IDC_AXISLABEL_EDIT,319,499,76,14,ES_AUTOHSCROLL + CONTROL "Pan",IDC_PAN_CHECK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,123,441,29,10 + CONTROL "Zoom",IDC_ZOOM_CHECK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,166,441,34,10 + CONTROL "ScrollBar",IDC_AXISSCROLLBAR_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,320,441,44,10 +END + +IDD_SERIESPROP_DLG DIALOG DISCARDABLE 0, 0, 449, 279 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Series properties" +FONT 8, "MS Sans Serif" +BEGIN + GROUPBOX "Series properties",IDC_STATIC,7,7,435,82 + LTEXT "Series type:",IDC_STATIC,45,25,66,8 + COMBOBOX IDC_SERIESTYPE_COMBO,123,23,62,54,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Series name:",IDC_STATIC,237,25,92,8 + EDITTEXT IDC_SERIESNAME_EDIT,341,22,63,14,ES_AUTOHSCROLL + LTEXT "Series colour:",IDC_STATIC,45,58,66,8 + PUSHBUTTON "",IDC_SERIESCOLOUR_BTN,123,55,38,14 + LTEXT "Associated vert axis:",IDC_STATIC,237,50,92,8 + COMBOBOX IDC_VERTICALAXIS_COMBO,341,48,48,49,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Associated horiz axis:",IDC_STATIC,237,67,92,8 + COMBOBOX IDC_HORIZONTALAXIS_COMBO,341,65,48,51,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + GROUPBOX "Series Data",IDC_STATIC,7,102,435,139 + CONTROL "Line Ò»ÔªÒ»´Î·½³Ì",IDC_LINEDATA_RADIO,"Button", + BS_AUTORADIOBUTTON,50,119,88,10 + CONTROL "Sine wave ÕýÏÒÇúÏß",IDC_SINEDATA_RADIO,"Button", + BS_AUTORADIOBUTTON,191,117,92,10 + CONTROL "Random data",IDC_RANDOMDATA_RADIO,"Button", + BS_AUTORADIOBUTTON,340,119,59,10 + RTEXT "Line Slope бÂÊ:",IDC_DATAPARAM1_TEXT,41,168,97,8 + EDITTEXT IDC_DATAPARAM1_EDIT,157,163,40,14,ES_AUTOHSCROLL + RTEXT "Line Offset Æ«ÒÆÁ¿:",IDC_DATAPARAM2_TEXT,232,168,107,8 + EDITTEXT IDC_DATAPARAM2_EDIT,351,165,40,14,ES_AUTOHSCROLL + LTEXT "Number of points µãÊýÁ¿:",IDC_STATIC,41,205,97,8 + EDITTEXT IDC_POINTSNUMBER_EDIT,157,201,40,14,ES_AUTOHSCROLL | + ES_NUMBER + LTEXT "Minimum X value XµÄ×îСֵ:",IDC_STATIC,232,194,107,8 + EDITTEXT IDC_MINXVALUE_EDIT,351,191,29,14,ES_AUTOHSCROLL + LTEXT "Maximum X value XµÄ×î´óÖµ:",IDC_STATIC,232,215,107,8 + EDITTEXT IDC_MAXXVALUE_EDIT,351,212,29,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,7,258,50,14 + PUSHBUTTON "Cancel",IDCANCEL,392,258,50,14 +END + +IDD_LINEPROP_DLG DIALOG DISCARDABLE 0, 0, 216, 96 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Line series properties" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,82,75,50,14 + COMBOBOX IDC_PENSTYLE_COMBO,105,17,79,61,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Pen style:",IDC_STATIC,35,19,53,8 + LTEXT "Line width:",IDC_STATIC,35,41,53,8 + EDITTEXT IDC_LINEWIDTH_EDIT,105,38,40,14,ES_AUTOHSCROLL +END + +IDD_SURFACEPROP_DLG DIALOG DISCARDABLE 0, 0, 267, 98 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Surface series properties" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,108,77,50,14 + LTEXT "Fill style:",IDC_STATIC,39,20,69,8 + CONTROL "Horizontal surface",IDC_HORIZONTAL_RADIO,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,30,46,92,10 + CONTROL "Vertical surface",IDC_RADIO2,"Button", + BS_AUTORADIOBUTTON,144,46,92,10 + COMBOBOX IDC_FILLSTYLE_COMBO,134,17,93,78,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP +END + +IDD_POINTPROP_DLG DIALOG DISCARDABLE 0, 0, 235, 101 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Points series properties" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,92,80,50,14 + LTEXT "Point type:",IDC_STATIC,34,16,53,8 + LTEXT "Point width:",IDC_STATIC,34,36,53,8 + LTEXT "Point height:",IDC_STATIC,34,56,53,8 + COMBOBOX IDC_POINTTYPE_COMBO,113,14,88,66,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_POINTWIDTH_EDIT,113,33,40,14,ES_AUTOHSCROLL | + ES_NUMBER + EDITTEXT IDC_POINTHEIGHT_EDIT,113,53,40,14,ES_AUTOHSCROLL | + ES_NUMBER +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040c04b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "\0" + VALUE "FileDescription", "Application MFC ChartDemo\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "ChartDemo\0" + VALUE "LegalCopyright", "Copyright (C) 2006\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "ChartDemo.EXE\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "Application ChartDemo\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x40c, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_CHARTDEMO_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 442 + TOPMARGIN, 7 + BOTTOMMARGIN, 536 + END + + IDD_SERIESPROP_DLG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 442 + TOPMARGIN, 7 + BOTTOMMARGIN, 272 + END + + IDD_LINEPROP_DLG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 209 + TOPMARGIN, 7 + BOTTOMMARGIN, 89 + END + + IDD_SURFACEPROP_DLG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 91 + END + + IDD_POINTPROP_DLG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 94 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog Info +// + +IDD_SERIESPROP_DLG DLGINIT +BEGIN + IDC_SERIESTYPE_COMBO, 0x403, 5, 0 +0x694c, 0x656e, "\000" + IDC_SERIESTYPE_COMBO, 0x403, 7, 0 +0x6f50, 0x6e69, 0x7374, "\000" + IDC_SERIESTYPE_COMBO, 0x403, 8, 0 +0x7553, 0x6672, 0x6361, 0x0065, + IDC_VERTICALAXIS_COMBO, 0x403, 5, 0 +0x654c, 0x7466, "\000" + IDC_VERTICALAXIS_COMBO, 0x403, 6, 0 +0x6952, 0x6867, 0x0074, + IDC_HORIZONTALAXIS_COMBO, 0x403, 7, 0 +0x6f42, 0x7474, 0x6d6f, "\000" + IDC_HORIZONTALAXIS_COMBO, 0x403, 4, 0 +0x6f54, 0x0070, + 0 +END + +IDD_LINEPROP_DLG DLGINIT +BEGIN + IDC_PENSTYLE_COMBO, 0x403, 11, 0 +0x6f53, 0x696c, 0x2064, 0xb5ca, 0xdfcf, "\000" + IDC_PENSTYLE_COMBO, 0x403, 10, 0 +0x6144, 0x6873, 0xd020, 0xcfe9, 0x00df, + IDC_PENSTYLE_COMBO, 0x403, 9, 0 +0x6f44, 0x2074, 0xe3b5, 0xdfcf, "\000" + IDC_PENSTYLE_COMBO, 0x403, 16, 0 +0x6144, 0x6873, 0x442d, 0x746f, 0xb520, 0xbbe3, 0xcfae, 0x00df, + IDC_PENSTYLE_COMBO, 0x403, 20, 0 +0x6144, 0x6873, 0x442d, 0x746f, 0x442d, 0x746f, 0xb520, 0xbbe3, 0xcfae, +0x00df, + 0 +END + +IDD_SURFACEPROP_DLG DLGINIT +BEGIN + IDC_FILLSTYLE_COMBO, 0x403, 6, 0 +0x6f53, 0x696c, 0x0064, + IDC_FILLSTYLE_COMBO, 0x403, 20, 0 +0x6148, 0x6374, 0x2068, 0x6f64, 0x6e77, 0x6420, 0x6169, 0x6f67, 0x616e, +0x006c, + IDC_FILLSTYLE_COMBO, 0x403, 18, 0 +0x6148, 0x6374, 0x2068, 0x7075, 0x6420, 0x6169, 0x6f67, 0x616e, 0x006c, + + IDC_FILLSTYLE_COMBO, 0x403, 12, 0 +0x6148, 0x6374, 0x2068, 0x7263, 0x736f, 0x0073, + IDC_FILLSTYLE_COMBO, 0x403, 22, 0 +0x6148, 0x6374, 0x2068, 0x7263, 0x736f, 0x2073, 0x6964, 0x6761, 0x6e6f, +0x6c61, 0x0020, + IDC_FILLSTYLE_COMBO, 0x403, 17, 0 +0x6148, 0x6374, 0x2068, 0x6f68, 0x6972, 0x6f7a, 0x746e, 0x6c61, "\000" + IDC_FILLSTYLE_COMBO, 0x403, 15, 0 +0x6148, 0x6374, 0x2068, 0x6576, 0x7472, 0x6369, 0x6c61, "\000" + 0 +END + +IDD_POINTPROP_DLG DLGINIT +BEGIN + IDC_POINTTYPE_COMBO, 0x403, 8, 0 +0x6c45, 0x696c, 0x7370, 0x0065, + IDC_POINTTYPE_COMBO, 0x403, 10, 0 +0x6552, 0x7463, 0x6e61, 0x6c67, 0x0065, + IDC_POINTTYPE_COMBO, 0x403, 9, 0 +0x7254, 0x6169, 0x676e, 0x656c, "\000" + 0 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_ABOUTBOX "&A propos de ChartDemo..." +END + +#endif // Chinese (P.R.C.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// French (France) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA) +#ifdef _WIN32 +LANGUAGE LANG_FRENCH, SUBLANG_FRENCH +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE MOVEABLE PURE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE MOVEABLE PURE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE MOVEABLE PURE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 12, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\ChartDemo.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""l.fra\\afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON DISCARDABLE "res\\ChartDemo.ico" +#endif // French (France) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA) +#ifdef _WIN32 +LANGUAGE 12, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\ChartDemo.rc2" // non-Microsoft Visual C++ edited resources +#include "l.fra\afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/ChartDemo/ChartDemo.sln b/ChartDemo/ChartDemo.sln new file mode 100644 index 0000000..956c631 --- /dev/null +++ b/ChartDemo/ChartDemo.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual C++ Express 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ChartDemo", "ChartDemo.vcproj", "{EFDCE8CF-7F5A-4BC4-A320-93563E1D0AF7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EFDCE8CF-7F5A-4BC4-A320-93563E1D0AF7}.Debug|Win32.ActiveCfg = Debug|Win32 + {EFDCE8CF-7F5A-4BC4-A320-93563E1D0AF7}.Debug|Win32.Build.0 = Debug|Win32 + {EFDCE8CF-7F5A-4BC4-A320-93563E1D0AF7}.Release|Win32.ActiveCfg = Release|Win32 + {EFDCE8CF-7F5A-4BC4-A320-93563E1D0AF7}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ChartDemo/ChartDemo.vcproj b/ChartDemo/ChartDemo.vcproj new file mode 100644 index 0000000..6e40d50 --- /dev/null +++ b/ChartDemo/ChartDemo.vcproj @@ -0,0 +1,656 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ChartDemo/ChartDemoDlg.cpp b/ChartDemo/ChartDemoDlg.cpp new file mode 100644 index 0000000..705de05 --- /dev/null +++ b/ChartDemo/ChartDemoDlg.cpp @@ -0,0 +1,751 @@ +// ChartDemoDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "ChartDemo.h" +#include "ChartDemoDlg.h" + +#include "ChartLineSerie.h" +#include "ChartPointsSerie.h" +#include "ChartSurfaceSerie.h" +#include "ChartGrid.h" + +#include "SeriesPropDlg.h" +#include "LinePropDialog.h" +#include "SurfacePropDialog.h" +#include "PointsPropDialog.h" + +#include "ChartBarSerie.h" +#include "ChartLabel.h" + +#include "ChartAxisLabel.h" +#include "ChartStandardAxis.h" +#include "ChartDateTimeAxis.h" + +#include "ChartCrossHairCursor.h" +#include "ChartDragLineCursor.h" + +#include +#include +#include +#include + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +using namespace std; + +///////////////////////////////////////////////////////////////////////////// +// CAboutDlg dialog used for App About + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// Dialog Data + //{{AFX_DATA(CAboutDlg) + enum { IDD = IDD_ABOUTBOX }; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAboutDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + //{{AFX_MSG(CAboutDlg) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ + //{{AFX_DATA_INIT(CAboutDlg) + //}}AFX_DATA_INIT +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAboutDlg) + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) + //{{AFX_MSG_MAP(CAboutDlg) + // No message handlers + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CChartDemoDlg dialog + +CChartDemoDlg::CChartDemoDlg(CWnd* pParent /*=NULL*/) + : CDialog(CChartDemoDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CChartDemoDlg) + //}}AFX_DATA_INIT + // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CChartDemoDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CChartDemoDlg) + DDX_Control(pDX, IDC_TITLE_EDIT, m_TitlesEdit); + DDX_Control(pDX, IDC_SERIES_LIST, m_SeriesList); + DDX_Control(pDX, IDC_AXISMINVAL_EDIT, m_AxisMinValEdit); + DDX_Control(pDX, IDC_AXISMAXVAL_EDIT, m_AxisMaxValEdit); + DDX_Control(pDX, IDC_LEGENDVIS_CHECK, m_LegendVisBtn); + DDX_Control(pDX, IDC_BKGND_COLBTN, m_BackgndColSel); + DDX_Control(pDX, IDC_CHARTCTRL, m_ChartCtrl); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CChartDemoDlg, CDialog) + //{{AFX_MSG_MAP(CChartDemoDlg) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED(IDC_ADDSERIES, OnAddseries) + ON_BN_CLICKED(IDC_LEGENDVIS_CHECK, OnLegendVisible) + ON_BN_CLICKED(IDC_BOTTOMAXIS_RADIO, OnBottomAxisRadio) + ON_BN_CLICKED(IDC_LEFTAXIS_RADIO, OnLeftAxisRadio) + ON_BN_CLICKED(IDC_RIGHTAXIS_RADIO, OnRightAxisRadio) + ON_BN_CLICKED(IDC_TOPAXIS_RADIO, OnTopAxisRadio) + ON_BN_CLICKED(IDC_AXISAUTOMATIC_CHECK, OnAxisAutomaticCheck) + ON_BN_CLICKED(IDC_AXISGRIDVIS_CHECK, OnAxisGridVisCheck) + ON_BN_CLICKED(IDC_AXISVISIBLE_CHECK, OnAxisVisibleCheck) + ON_BN_CLICKED(IDC_AXISSCROLLBAR_CHECK, OnAxisScrollBarCheck) + ON_MESSAGE(CPN_SELENDOK, OnChangeBckCol) + ON_EN_KILLFOCUS(IDC_AXISMAXVAL_EDIT, OnChangeAxisMax) + ON_EN_KILLFOCUS(IDC_AXISMINVAL_EDIT, OnChangeAxisMin) + ON_BN_CLICKED(IDC_AXISINVERTED_CHECK, OnAxisInvertedCheck) + ON_EN_KILLFOCUS(IDC_AXISLABEL_EDIT, OnChangeAxisLabel) + ON_BN_CLICKED(IDC_DELETESERIES, OnDeleteSeries) + ON_EN_KILLFOCUS(IDC_TITLE_EDIT, OnChangeTitle) + ON_BN_CLICKED(IDC_PAN_CHECK, OnPanCheck) + ON_BN_CLICKED(IDC_ZOOM_CHECK, OnZoomCheck) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CChartDemoDlg message handlers + +BOOL CChartDemoDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // Add "About..." menu item to system menu. + + // IDM_ABOUTBOX must be in the system command range. + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) + { + CString strAboutMenu; + strAboutMenu.LoadString(IDS_ABOUTBOX); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // Set the icon for this dialog. The framework does this automatically + // when the application's main window is not a dialog + SetIcon(m_hIcon, TRUE); // Set big icon + SetIcon(m_hIcon, FALSE); // Set small icon + + COLORREF BackColor = 0x00eeeeaf; + m_BackgndColSel.SetColour(BackColor); + m_ChartCtrl.SetBackColor(BackColor); + + ((CButton*)GetDlgItem(IDC_LEFTAXIS_RADIO))->SetCheck(1); + ((CButton*)GetDlgItem(IDC_PAN_CHECK))->SetCheck(1); + ((CButton*)GetDlgItem(IDC_ZOOM_CHECK))->SetCheck(1); + + CChartStandardAxis* pBottomAxis = + m_ChartCtrl.CreateStandardAxis(CChartCtrl::BottomAxis); + pBottomAxis->SetMinMax(0, 10); + CChartStandardAxis* pLeftAxis = + m_ChartCtrl.CreateStandardAxis(CChartCtrl::LeftAxis); + pLeftAxis->SetMinMax(0, 10); + CChartStandardAxis* pTopAxis = + m_ChartCtrl.CreateStandardAxis(CChartCtrl::TopAxis); + pTopAxis->SetMinMax(0, 10); + CChartStandardAxis* pRightAxis = + m_ChartCtrl.CreateStandardAxis(CChartCtrl::RightAxis); + pRightAxis->SetMinMax(0, 10); + + OnLeftAxisRadio(); + return TRUE; // return TRUE unless you set the focus to a control +} + +void CChartDemoDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialog::OnSysCommand(nID, lParam); + } +} + +// If you add a minimize button to your dialog, you will need the code below +// to draw the icon. For MFC applications using the document/view model, +// this is automatically done for you by the framework. + +void CChartDemoDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // device context for painting + + SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); + + // Center icon in client rectangle + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // Draw the icon + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +// The system calls this to obtain the cursor to display while the user drags +// the minimized window. +HCURSOR CChartDemoDlg::OnQueryDragIcon() +{ + return (HCURSOR) m_hIcon; +} + + +void CChartDemoDlg::OnAddseries() +{ + CSeriesPropDlg PropertiesDlg; + if (PropertiesDlg.DoModal() == IDCANCEL) + return; + + int Type = PropertiesDlg.m_iSeriesType; + TChartString Name = PropertiesDlg.m_strSeriesName; + COLORREF Color = PropertiesDlg.m_SeriesColour; + + CChartXYSerie* pSeries = NULL; + INT_PTR nPropDlgRet = -1; + switch (Type) + { + // Line series + case 0: + { + bool bSecondHorizAxis = (PropertiesDlg.m_iHorizAxis == 1); + bool bSecondVertAxis = (PropertiesDlg.m_iVertAxis == 1); + CChartLineSerie* pLineSeries = m_ChartCtrl.CreateLineSerie(bSecondHorizAxis, bSecondVertAxis); + pSeries = pLineSeries; + + CLinePropDialog LinePropDlg; + nPropDlgRet = LinePropDlg.DoModal(); + + pLineSeries->SetWidth(LinePropDlg.m_iLineWidth); + pLineSeries->SetPenStyle(LinePropDlg.m_iPenStyle); + } + break; + + // Points series + case 1: + { + bool bSecondHorizAxis = (PropertiesDlg.m_iHorizAxis == 1); + bool bSecondVertAxis = (PropertiesDlg.m_iVertAxis == 1); + CChartPointsSerie* pPointsSeries = m_ChartCtrl.CreatePointsSerie(bSecondHorizAxis, bSecondVertAxis); + pSeries = pPointsSeries; + + CPointsPropDialog PointsPropDlg; + nPropDlgRet = PointsPropDlg.DoModal(); + + switch (PointsPropDlg.m_iPointsType) + { + case 0: + pPointsSeries->SetPointType(CChartPointsSerie::ptEllipse); + break; + + case 1: + pPointsSeries->SetPointType(CChartPointsSerie::ptRectangle); + break; + + case 2: + pPointsSeries->SetPointType(CChartPointsSerie::ptTriangle); + break; + } + + pPointsSeries->SetPointSize(PointsPropDlg.m_iPointsWidth,PointsPropDlg.m_iPointsHeight); + } + break; + + // Surface series + case 2: + { + bool bSecondHorizAxis = (PropertiesDlg.m_iHorizAxis == 1); + bool bSecondVertAxis = (PropertiesDlg.m_iVertAxis == 1); + CChartSurfaceSerie* pSurfSeries = m_ChartCtrl.CreateSurfaceSerie(bSecondHorizAxis, bSecondVertAxis); + pSeries = pSurfSeries; + + CSurfacePropDialog SurfPropDlg; + nPropDlgRet = SurfPropDlg.DoModal(); + + switch (SurfPropDlg.m_FillStyle) + { + case 0: + pSurfSeries->SetFillStyle(CChartSurfaceSerie::fsSolid); + break; + case 1: + pSurfSeries->SetFillStyle(CChartSurfaceSerie::fsHatchDownDiag); + break; + case 2: + pSurfSeries->SetFillStyle(CChartSurfaceSerie::fsHatchUpDiag); + break; + case 3: + pSurfSeries->SetFillStyle(CChartSurfaceSerie::fsHatchCross); + break; + case 4: + pSurfSeries->SetFillStyle(CChartSurfaceSerie::fsHatchDiagCross); + break; + case 5: + pSurfSeries->SetFillStyle(CChartSurfaceSerie::fsHatchHorizontal); + break; + case 6: + pSurfSeries->SetFillStyle(CChartSurfaceSerie::fsHatchVertical); + break; + } + + if (SurfPropDlg.m_iHorizSurf == 0) + pSurfSeries->SetHorizontal(true); + else + pSurfSeries->SetHorizontal(false); + } + break; + } + + if(nPropDlgRet ==IDCANCEL){ + return; + } + + pSeries->SetName(Name); + pSeries->SetColor(Color); + + int NumberPoints = PropertiesDlg.m_iPointsNumber; + double* XValues = new double[NumberPoints]; + double* YValues = new double[NumberPoints]; + float Step = (PropertiesDlg.m_fMaxXValue - PropertiesDlg.m_fMinXValue)/(NumberPoints - 1); + float XStart = PropertiesDlg.m_fMinXValue; + switch (PropertiesDlg.m_iDataType) + { + case 0: + { + float Slope = PropertiesDlg.m_fLineSlope; + float Offset = PropertiesDlg.m_fLineOffset; + + for (int i=0;iSetPoints(XValues,YValues,NumberPoints); + + } + break; + + case 1: + { + float Amplitude = PropertiesDlg.m_fSineAmplitude; + float Period = PropertiesDlg.m_fSinePeriod; + + for (int i=0;iSetPoints(XValues,YValues,NumberPoints); + } + break; + + case 2: + { + int Min = PropertiesDlg.m_iRandMinVal; + int Max = PropertiesDlg.m_iRandMaxVal; + srand((unsigned int)time(NULL)); + for (int i=0;iSetPoints(XValues,YValues,NumberPoints); + } + break; + } + + delete[] XValues; + delete[] YValues; + m_ChartCtrl.RefreshCtrl(); + int index = m_SeriesList.AddString(Name.c_str()); + m_SeriesList.SetItemData(index, pSeries->GetSerieId()); +} + +void CChartDemoDlg::OnLegendVisible() +{ + if (m_LegendVisBtn.GetCheck() == 1) + m_ChartCtrl.GetLegend()->SetVisible(true); + else + m_ChartCtrl.GetLegend()->SetVisible(false); + m_ChartCtrl.RefreshCtrl(); +} + +void CChartDemoDlg::OnBottomAxisRadio() +{ + CChartAxis* pAxis = m_ChartCtrl.GetBottomAxis(); + if (pAxis->IsVisible()) + ((CButton*)GetDlgItem(IDC_AXISVISIBLE_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISVISIBLE_CHECK))->SetCheck(0); + if (pAxis->GetGrid()->IsVisible()) + ((CButton*)GetDlgItem(IDC_AXISGRIDVIS_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISGRIDVIS_CHECK))->SetCheck(0); + if (pAxis->IsAutomatic()) + ((CButton*)GetDlgItem(IDC_AXISAUTOMATIC_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISAUTOMATIC_CHECK))->SetCheck(0); + if (pAxis->IsInverted()) + ((CButton*)GetDlgItem(IDC_AXISINVERTED_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISINVERTED_CHECK))->SetCheck(0); + if (pAxis->ScrollBarEnabled()) + ((CButton*)GetDlgItem(IDC_AXISSCROLLBAR_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISSCROLLBAR_CHECK))->SetCheck(0); + + TChartString AxisLabel = pAxis->GetLabel()->GetText(); + GetDlgItem(IDC_AXISLABEL_EDIT)->SetWindowText(AxisLabel.c_str()); + + double Min=0, Max=0; + CString strBuff; + pAxis->GetMinMax(Min,Max); + strBuff.Format(_T("%.2f"),Min); + GetDlgItem(IDC_AXISMINVAL_EDIT)->SetWindowText(strBuff); + strBuff.Format(_T("%.2f"),Max); + GetDlgItem(IDC_AXISMAXVAL_EDIT)->SetWindowText(strBuff); +} + +void CChartDemoDlg::OnLeftAxisRadio() +{ + CChartAxis* pAxis = m_ChartCtrl.GetLeftAxis(); + if (pAxis->IsVisible()) + ((CButton*)GetDlgItem(IDC_AXISVISIBLE_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISVISIBLE_CHECK))->SetCheck(0); + if (pAxis->GetGrid()->IsVisible()) + ((CButton*)GetDlgItem(IDC_AXISGRIDVIS_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISGRIDVIS_CHECK))->SetCheck(0); + if (pAxis->IsAutomatic()) + ((CButton*)GetDlgItem(IDC_AXISAUTOMATIC_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISAUTOMATIC_CHECK))->SetCheck(0); + if (pAxis->IsInverted()) + ((CButton*)GetDlgItem(IDC_AXISINVERTED_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISINVERTED_CHECK))->SetCheck(0); + if (pAxis->ScrollBarEnabled()) + ((CButton*)GetDlgItem(IDC_AXISSCROLLBAR_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISSCROLLBAR_CHECK))->SetCheck(0); + + TChartString AxisLabel = pAxis->GetLabel()->GetText(); + GetDlgItem(IDC_AXISLABEL_EDIT)->SetWindowText(AxisLabel.c_str()); + + double Min=0, Max=0; + CString strBuff; + pAxis->GetMinMax(Min,Max); + strBuff.Format(_T("%.2f"),Min); + GetDlgItem(IDC_AXISMINVAL_EDIT)->SetWindowText(strBuff); + strBuff.Format(_T("%.2f"),Max); + GetDlgItem(IDC_AXISMAXVAL_EDIT)->SetWindowText(strBuff); +} + +void CChartDemoDlg::OnRightAxisRadio() +{ + CChartAxis* pAxis = m_ChartCtrl.GetRightAxis(); + if (pAxis->IsVisible()) + ((CButton*)GetDlgItem(IDC_AXISVISIBLE_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISVISIBLE_CHECK))->SetCheck(0); + if (pAxis->GetGrid()->IsVisible()) + ((CButton*)GetDlgItem(IDC_AXISGRIDVIS_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISGRIDVIS_CHECK))->SetCheck(0); + if (pAxis->IsAutomatic()) + ((CButton*)GetDlgItem(IDC_AXISAUTOMATIC_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISAUTOMATIC_CHECK))->SetCheck(0); + if (pAxis->IsInverted()) + ((CButton*)GetDlgItem(IDC_AXISINVERTED_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISINVERTED_CHECK))->SetCheck(0); + if (pAxis->ScrollBarEnabled()) + ((CButton*)GetDlgItem(IDC_AXISSCROLLBAR_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISSCROLLBAR_CHECK))->SetCheck(0); + + TChartString AxisLabel = pAxis->GetLabel()->GetText(); + GetDlgItem(IDC_AXISLABEL_EDIT)->SetWindowText(AxisLabel.c_str()); + + double Min=0, Max=0; + CString strBuff; + pAxis->GetMinMax(Min,Max); + strBuff.Format(_T("%.2f"),Min); + GetDlgItem(IDC_AXISMINVAL_EDIT)->SetWindowText(strBuff); + strBuff.Format(_T("%.2f"),Max); + GetDlgItem(IDC_AXISMAXVAL_EDIT)->SetWindowText(strBuff); +} + +void CChartDemoDlg::OnTopAxisRadio() +{ + CChartAxis* pAxis = m_ChartCtrl.GetTopAxis(); + if (pAxis->IsVisible()) + ((CButton*)GetDlgItem(IDC_AXISVISIBLE_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISVISIBLE_CHECK))->SetCheck(0); + if (pAxis->GetGrid()->IsVisible()) + ((CButton*)GetDlgItem(IDC_AXISGRIDVIS_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISGRIDVIS_CHECK))->SetCheck(0); + if (pAxis->IsAutomatic()) + ((CButton*)GetDlgItem(IDC_AXISAUTOMATIC_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISAUTOMATIC_CHECK))->SetCheck(0); + if (pAxis->IsInverted()) + ((CButton*)GetDlgItem(IDC_AXISINVERTED_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISINVERTED_CHECK))->SetCheck(0); + if (pAxis->ScrollBarEnabled()) + ((CButton*)GetDlgItem(IDC_AXISSCROLLBAR_CHECK))->SetCheck(1); + else + ((CButton*)GetDlgItem(IDC_AXISSCROLLBAR_CHECK))->SetCheck(0); + + TChartString AxisLabel = pAxis->GetLabel()->GetText(); + GetDlgItem(IDC_AXISLABEL_EDIT)->SetWindowText(AxisLabel.c_str()); + + double Min=0, Max=0; + CString strBuff; + pAxis->GetMinMax(Min,Max); + strBuff.Format(_T("%.2f"),Min); + GetDlgItem(IDC_AXISMINVAL_EDIT)->SetWindowText(strBuff); + strBuff.Format(_T("%.2f"),Max); + GetDlgItem(IDC_AXISMAXVAL_EDIT)->SetWindowText(strBuff); +} + +void CChartDemoDlg::OnAxisAutomaticCheck() +{ + CChartAxis* pAxis = GetSelectedAxis(); + if ( ((CButton*)GetDlgItem(IDC_AXISAUTOMATIC_CHECK))->GetCheck() == 1) + pAxis->SetAutomatic(true); + else + { + TCHAR szBuffer[255]; + double MinVal=0, MaxVal=0; + m_AxisMinValEdit.GetWindowText(szBuffer,254); +// MinVal = _tstof(szBuffer); + MinVal = _tcstod(szBuffer, NULL); + m_AxisMaxValEdit.GetWindowText(szBuffer,254); +// MaxVal = _tstof(szBuffer); + MaxVal = _tcstod(szBuffer, NULL); + + if (MinVal > MaxVal) + { + MessageBox(_T("MinVal > MaxVal"),_T("Error"),MB_OK); + ((CButton*)GetDlgItem(IDC_AXISAUTOMATIC_CHECK))->SetCheck(1); + return; + } + pAxis->SetAutomatic(false); + pAxis->SetMinMax(MinVal,MaxVal); + } + m_ChartCtrl.RefreshCtrl(); +} + +void CChartDemoDlg::OnAxisGridVisCheck() +{ + CChartAxis* pAxis = GetSelectedAxis(); + if ( ((CButton*)GetDlgItem(IDC_AXISGRIDVIS_CHECK))->GetCheck() == 1) + pAxis->GetGrid()->SetVisible(true); + else + pAxis->GetGrid()->SetVisible(false); + m_ChartCtrl.RefreshCtrl(); +} + +void CChartDemoDlg::OnAxisVisibleCheck() +{ + CChartAxis* pAxis = GetSelectedAxis(); + if ( ((CButton*)GetDlgItem(IDC_AXISVISIBLE_CHECK))->GetCheck() == 1) + pAxis->SetVisible(true); + else + pAxis->SetVisible(false); + m_ChartCtrl.RefreshCtrl(); +} + +void CChartDemoDlg::OnAxisInvertedCheck() +{ + CChartAxis* pAxis = GetSelectedAxis(); + if ( ((CButton*)GetDlgItem(IDC_AXISINVERTED_CHECK))->GetCheck() == 1) + pAxis->SetInverted(true); + else + pAxis->SetInverted(false); + m_ChartCtrl.RefreshCtrl(); +} + +void CChartDemoDlg::OnAxisScrollBarCheck() +{ + CChartAxis* pAxis = GetSelectedAxis(); + bool bShow = ((CButton*)GetDlgItem(IDC_AXISSCROLLBAR_CHECK))->GetCheck() == 1; + pAxis->EnableScrollBar(bShow); +} + +CChartAxis* CChartDemoDlg::GetSelectedAxis() +{ + if ( ((CButton*)GetDlgItem(IDC_LEFTAXIS_RADIO))->GetCheck() == 1) + return m_ChartCtrl.GetLeftAxis(); + if ( ((CButton*)GetDlgItem(IDC_BOTTOMAXIS_RADIO))->GetCheck() == 1) + return m_ChartCtrl.GetBottomAxis(); + if ( ((CButton*)GetDlgItem(IDC_RIGHTAXIS_RADIO))->GetCheck() == 1) + return m_ChartCtrl.GetRightAxis(); + if ( ((CButton*)GetDlgItem(IDC_TOPAXIS_RADIO))->GetCheck() == 1) + return m_ChartCtrl.GetTopAxis(); + + return NULL; +} + +LONG CChartDemoDlg::OnChangeBckCol(UINT , LONG ) +{ + COLORREF BackColor = m_BackgndColSel.GetColour(); + m_ChartCtrl.SetBackColor(BackColor); + m_ChartCtrl.RefreshCtrl(); + return TRUE; +} + +void CChartDemoDlg::OnChangeAxisMax() +{ + CChartAxis* pAxis = GetSelectedAxis(); + TCHAR szBuffer[255]; + double MinVal=0, MaxVal=0; + m_AxisMinValEdit.GetWindowText(szBuffer,254); +// MinVal = _tstof(szBuffer); + MinVal = _tcstod(szBuffer, NULL); + m_AxisMaxValEdit.GetWindowText(szBuffer,254); +// MaxVal = _tstof(szBuffer); + MaxVal = _tcstod(szBuffer, NULL); + + if (MinVal > MaxVal) + { + MessageBox(_T("MinVal > MaxVal"),_T("Error"),MB_OK); + return; + } + pAxis->SetMinMax(MinVal,MaxVal); + + m_ChartCtrl.RefreshCtrl(); + +} + +void CChartDemoDlg::OnChangeAxisMin() +{ + CChartAxis* pAxis = GetSelectedAxis(); + TCHAR szBuffer[255]; + double MinVal=0, MaxVal=0; + m_AxisMinValEdit.GetWindowText(szBuffer,254); +// MinVal = _tstof(szBuffer); + MinVal = _tcstod(szBuffer, NULL); + m_AxisMaxValEdit.GetWindowText(szBuffer,254); +// MaxVal = _tstof(szBuffer); + MaxVal = _tcstod(szBuffer, NULL); + + if (MinVal > MaxVal) + { + MessageBox(_T("MinVal > MaxVal"),_T("Error"),MB_OK); + return; + } + pAxis->SetMinMax(MinVal,MaxVal); + + m_ChartCtrl.RefreshCtrl(); +} + +void CChartDemoDlg::OnChangeAxisLabel() +{ + CChartAxis* pAxis = GetSelectedAxis(); + TCHAR szBuffer[255]; + GetDlgItem(IDC_AXISLABEL_EDIT)->GetWindowText(szBuffer,254); + pAxis->GetLabel()->SetText(szBuffer); + m_ChartCtrl.RefreshCtrl(); + +} + +void CChartDemoDlg::OnDeleteSeries() +{ + int Index = m_SeriesList.GetCurSel(); + if (Index == -1) + return; + unsigned seriesId = m_SeriesList.GetItemData(Index); + + m_ChartCtrl.RemoveSerie(seriesId); + m_SeriesList.DeleteString(Index); +} + +void CChartDemoDlg::OnChangeTitle() +{ + int Count = m_TitlesEdit.GetLineCount(); + CChartTitle* pTitle = m_ChartCtrl.GetTitle(); + pTitle->RemoveAll(); + + TCHAR szBuff[255]; + for (int i=0;iAddString(szBuff); + } + + m_ChartCtrl.RefreshCtrl(); +} + +void CChartDemoDlg::OnPanCheck() +{ + if ( ((CButton*)GetDlgItem(IDC_PAN_CHECK))->GetCheck() == 1) + m_ChartCtrl.SetPanEnabled(true); + else + m_ChartCtrl.SetPanEnabled(false); + +} + +void CChartDemoDlg::OnZoomCheck() +{ + if ( ((CButton*)GetDlgItem(IDC_ZOOM_CHECK))->GetCheck() == 1) + m_ChartCtrl.SetZoomEnabled(true); + else + m_ChartCtrl.SetZoomEnabled(false); +} \ No newline at end of file diff --git a/ChartDemo/ChartDemoDlg.h b/ChartDemo/ChartDemoDlg.h new file mode 100644 index 0000000..6b67596 --- /dev/null +++ b/ChartDemo/ChartDemoDlg.h @@ -0,0 +1,82 @@ +// ChartDemoDlg.h : header file +// + +#if !defined(AFX_CHARTDEMODLG_H__1C3B17D7_0821_47FC_B873_9D9337728F79__INCLUDED_) +#define AFX_CHARTDEMODLG_H__1C3B17D7_0821_47FC_B873_9D9337728F79__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "ChartCtrl.h" +#include "ColourPicker.h" +#include "ChartLineSerie.h" + +///////////////////////////////////////////////////////////////////////////// +// CChartDemoDlg dialog + +class CChartDemoDlg : public CDialog +{ +// Construction +public: + CChartDemoDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CChartDemoDlg) + enum { IDD = IDD_CHARTDEMO_DIALOG }; + CEdit m_TitlesEdit; + CListBox m_SeriesList; + CEdit m_AxisMinValEdit; + CEdit m_AxisMaxValEdit; + CButton m_LegendVisBtn; + CColourPicker m_BackgndColSel; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CChartDemoDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + HICON m_hIcon; + + // Generated message map functions + //{{AFX_MSG(CChartDemoDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnAddseries(); + afx_msg void OnLegendVisible(); + afx_msg void OnBottomAxisRadio(); + afx_msg void OnLeftAxisRadio(); + afx_msg void OnRightAxisRadio(); + afx_msg void OnTopAxisRadio(); + afx_msg void OnAxisAutomaticCheck(); + afx_msg void OnAxisGridVisCheck(); + afx_msg void OnAxisVisibleCheck(); + afx_msg void OnAxisScrollBarCheck(); + afx_msg LONG OnChangeBckCol(UINT lParam, LONG wParam); + afx_msg void OnChangeAxisMax(); + afx_msg void OnChangeAxisMin(); + afx_msg void OnAxisInvertedCheck(); + afx_msg void OnChangeAxisLabel(); + afx_msg void OnDeleteSeries(); + afx_msg void OnChangeTitle(); + afx_msg void OnPanCheck(); + afx_msg void OnZoomCheck(); + afx_msg void OnSaveImage(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + + CChartAxis* GetSelectedAxis(); + + CChartCtrl m_ChartCtrl; +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_CHARTDEMODLG_H__1C3B17D7_0821_47FC_B873_9D9337728F79__INCLUDED_) diff --git a/ChartDemo/ColourPicker/ColourPicker.cpp b/ChartDemo/ColourPicker/ColourPicker.cpp new file mode 100644 index 0000000..35a7ce7 --- /dev/null +++ b/ChartDemo/ColourPicker/ColourPicker.cpp @@ -0,0 +1,309 @@ +// ColourPicker.cpp : implementation file +// +// ColourPicker is a drop-in colour picker control. Check out the +// header file or the accompanying HTML doc file for details. +// +// Written by Chris Maunder (chrismaunder@codeguru.com) +// Extended by Alexander Bischofberger (bischofb@informatik.tu-muenchen.de) +// Copyright (c) 1998. +// +// This code may be used in compiled form in any way you desire. This +// file may be redistributed unmodified by any means PROVIDING it is +// not sold for profit without the authors written consent, and +// providing that this notice and the authors name is included. If +// the source code in this file is used in any commercial application +// then a simple email would be nice. +// +// This file is provided "as is" with no expressed or implied warranty. +// The author accepts no liability if it causes any damage to your +// computer, causes your pet cat to fall ill, increases baldness or +// makes you car start emitting strange noises when you start it up. +// +// Expect bugs. +// +// Please use and enjoy. Please let me know of any bugs/mods/improvements +// that you have found/implemented and I will fix/incorporate them into this +// file. +// +// Updated 16 May 1998 +// 31 May 1998 - added Default text (CJM) +// 9 Jan 1999 - minor vis update + +#include "stdafx.h" +#include "ColourPopup.h" +#include "ColourPicker.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +void AFXAPI DDX_ColourPicker(CDataExchange *pDX, int nIDC, COLORREF& crColour) +{ + HWND hWndCtrl = pDX->PrepareCtrl(nIDC); + ASSERT (hWndCtrl != NULL); + + CColourPicker* pColourPicker = (CColourPicker*) CWnd::FromHandle(hWndCtrl); + if (pDX->m_bSaveAndValidate) + { + crColour = pColourPicker->GetColour(); + } + else // initializing + { + pColourPicker->SetColour(crColour); + } +} + +///////////////////////////////////////////////////////////////////////////// +// CColourPicker + +CColourPicker::CColourPicker() +{ + SetBkColour(GetSysColor(COLOR_3DFACE)); + SetTextColour(GetSysColor(COLOR_BTNTEXT)); + + m_bTrackSelection = FALSE; + m_nSelectionMode = CP_MODE_BK; + m_bActive = FALSE; + + m_strDefaultText = _T("Automatic"); + m_strCustomText = _T("More Colours..."); +} + +CColourPicker::~CColourPicker() +{ +} + +IMPLEMENT_DYNCREATE(CColourPicker, CButton) + +BEGIN_MESSAGE_MAP(CColourPicker, CButton) + //{{AFX_MSG_MAP(CColourPicker) + ON_CONTROL_REFLECT_EX(BN_CLICKED, OnClicked) + ON_WM_CREATE() + //}}AFX_MSG_MAP + ON_MESSAGE(CPN_SELENDOK, OnSelEndOK) + ON_MESSAGE(CPN_SELENDCANCEL, OnSelEndCancel) + ON_MESSAGE(CPN_SELCHANGE, OnSelChange) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CColourPicker message handlers + +LONG CColourPicker::OnSelEndOK(UINT lParam, LONG /*wParam*/) +{ + COLORREF crNewColour = (COLORREF) lParam; + m_bActive = FALSE; + SetColour(crNewColour); + + CWnd *pParent = GetParent(); + if (pParent) { + pParent->SendMessage(CPN_CLOSEUP, lParam, (WPARAM) GetDlgCtrlID()); + pParent->SendMessage(CPN_SELENDOK, lParam, (WPARAM) GetDlgCtrlID()); + } + + if (crNewColour != GetColour()) + if (pParent) pParent->SendMessage(CPN_SELCHANGE, lParam, (WPARAM) GetDlgCtrlID()); + + return TRUE; +} + +LONG CColourPicker::OnSelEndCancel(UINT lParam, LONG /*wParam*/) +{ + m_bActive = FALSE; + SetColour((COLORREF) lParam); + + CWnd *pParent = GetParent(); + if (pParent) { + pParent->SendMessage(CPN_CLOSEUP, lParam, (WPARAM) GetDlgCtrlID()); + pParent->SendMessage(CPN_SELENDCANCEL, lParam, (WPARAM) GetDlgCtrlID()); + } + + return TRUE; +} + +LONG CColourPicker::OnSelChange(UINT lParam, LONG /*wParam*/) +{ + if (m_bTrackSelection) SetColour((COLORREF) lParam); + + CWnd *pParent = GetParent(); + if (pParent) pParent->SendMessage(CPN_SELCHANGE, lParam, (WPARAM) GetDlgCtrlID()); + + return TRUE; +} + +int CColourPicker::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CButton::OnCreate(lpCreateStruct) == -1) + return -1; + + SetWindowSize(); // resize appropriately + return 0; +} + +// On mouse click, create and show a CColourPopup window for colour selection +BOOL CColourPicker::OnClicked() +{ + m_bActive = TRUE; + CRect rect; + GetWindowRect(rect); + new CColourPopup(CPoint(rect.left, rect.bottom), // Point to display popup + GetColour(), // Selected colour + this, // parent + m_strDefaultText, // "Default" text area + m_strCustomText); // Custom Text + + CWnd *pParent = GetParent(); + if (pParent) + pParent->SendMessage(CPN_DROPDOWN, (LPARAM)GetColour(), (WPARAM) GetDlgCtrlID()); + + // Docs say I should return FALSE to stop the parent also getting the message. + // HA! What a joke. + + return TRUE; +} + +void CColourPicker::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + ASSERT(lpDrawItemStruct); + + CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); + CRect rect = lpDrawItemStruct->rcItem; + UINT state = lpDrawItemStruct->itemState; + CString m_strText; + + CSize Margins(::GetSystemMetrics(SM_CXEDGE), ::GetSystemMetrics(SM_CYEDGE)); + + // Draw arrow + if (m_bActive) state |= ODS_SELECTED; + pDC->DrawFrameControl(&m_ArrowRect, DFC_SCROLL, DFCS_SCROLLDOWN | + ((state & ODS_SELECTED) ? DFCS_PUSHED : 0) | + ((state & ODS_DISABLED) ? DFCS_INACTIVE : 0)); + + pDC->DrawEdge(rect, EDGE_SUNKEN, BF_RECT); + + // Must reduce the size of the "client" area of the button due to edge thickness. + rect.DeflateRect(Margins.cx, Margins.cy); + + // Fill remaining area with colour + rect.right -= m_ArrowRect.Width(); + + CBrush brush( ((state & ODS_DISABLED) || m_crColourBk == CLR_DEFAULT)? + ::GetSysColor(COLOR_3DFACE) : m_crColourBk); + CBrush* pOldBrush = (CBrush*) pDC->SelectObject(&brush); + pDC->SelectStockObject(NULL_PEN); + pDC->Rectangle(rect); + pDC->SelectObject(pOldBrush); + + // Draw the window text (if any) + GetWindowText(m_strText); + if (m_strText.GetLength()) + { + pDC->SetBkMode(TRANSPARENT); + if (state & ODS_DISABLED) + { + rect.OffsetRect(1,1); + pDC->SetTextColor(::GetSysColor(COLOR_3DHILIGHT)); + pDC->DrawText(m_strText, rect, DT_CENTER|DT_SINGLELINE|DT_VCENTER); + rect.OffsetRect(-1,-1); + pDC->SetTextColor(::GetSysColor(COLOR_3DSHADOW)); + pDC->DrawText(m_strText, rect, DT_CENTER|DT_SINGLELINE|DT_VCENTER); + } + else + { + pDC->SetTextColor((m_crColourText == CLR_DEFAULT)? 0 : m_crColourText); + pDC->DrawText(m_strText, rect, DT_CENTER|DT_SINGLELINE|DT_VCENTER); + } + } + + // Draw focus rect + if (state & ODS_FOCUS) + { + rect.DeflateRect(1,1); + pDC->DrawFocusRect(rect); + } +} + +///////////////////////////////////////////////////////////////////////////// +// CColourPicker overrides + +void CColourPicker::PreSubclassWindow() +{ + ModifyStyle(0, BS_OWNERDRAW); // Make it owner drawn + CButton::PreSubclassWindow(); + SetWindowSize(); // resize appropriately +} + +///////////////////////////////////////////////////////////////////////////// +// CColourPicker attributes + +COLORREF CColourPicker::GetColour() +{ + return (m_nSelectionMode == CP_MODE_TEXT)? + GetTextColour(): GetBkColour(); +} + +void CColourPicker::SetColour(COLORREF crColour) +{ + (m_nSelectionMode == CP_MODE_TEXT)? + SetTextColour(crColour): SetBkColour(crColour); +} + +void CColourPicker::SetBkColour(COLORREF crColourBk) +{ + m_crColourBk = crColourBk; + if (IsWindow(m_hWnd)) + RedrawWindow(); +} + +void CColourPicker::SetTextColour(COLORREF crColourText) +{ + m_crColourText = crColourText; + if (IsWindow(m_hWnd)) + RedrawWindow(); +} + +void CColourPicker::SetDefaultText(LPCTSTR szDefaultText) +{ + m_strDefaultText = (szDefaultText)? szDefaultText : _T(""); +} + +void CColourPicker::SetCustomText(LPCTSTR szCustomText) +{ + m_strCustomText = (szCustomText)? szCustomText : _T(""); +} + +///////////////////////////////////////////////////////////////////////////// +// CColourPicker implementation + +void CColourPicker::SetWindowSize() +{ + // Get size dimensions of edges + CSize MarginSize(::GetSystemMetrics(SM_CXEDGE), ::GetSystemMetrics(SM_CYEDGE)); + + // Get size of dropdown arrow + int nArrowWidth = max(::GetSystemMetrics(SM_CXHTHUMB), 5*MarginSize.cx); + int nArrowHeight = max(::GetSystemMetrics(SM_CYVTHUMB), 5*MarginSize.cy); + CSize ArrowSize(max(nArrowWidth, nArrowHeight), max(nArrowWidth, nArrowHeight)); + + // Get window size + CRect rect; + GetWindowRect(rect); + + CWnd* pParent = GetParent(); + if (pParent) + pParent->ScreenToClient(rect); + + // Set window size at least as wide as 2 arrows, and as high as arrow + margins + int nWidth = max(rect.Width(), 2*ArrowSize.cx + 2*MarginSize.cx); + MoveWindow(rect.left, rect.top, nWidth, ArrowSize.cy+2*MarginSize.cy, TRUE); + + // Get the new coords of this window + GetWindowRect(rect); + ScreenToClient(rect); + + // Get the rect where the arrow goes, and convert to client coords. + m_ArrowRect.SetRect(rect.right - ArrowSize.cx - MarginSize.cx, + rect.top + MarginSize.cy, rect.right - MarginSize.cx, + rect.bottom - MarginSize.cy); +} diff --git a/ChartDemo/ColourPicker/ColourPicker.h b/ChartDemo/ColourPicker/ColourPicker.h new file mode 100644 index 0000000..0c2d7ac --- /dev/null +++ b/ChartDemo/ColourPicker/ColourPicker.h @@ -0,0 +1,113 @@ +#if !defined(AFX_COLOURPICKER_H__D0B75901_9830_11D1_9C0F_00A0243D1382__INCLUDED_) +#define AFX_COLOURPICKER_H__D0B75901_9830_11D1_9C0F_00A0243D1382__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +// ColourPicker.h : header file +// +// Written by Chris Maunder (chrismaunder@codeguru.com) +// Extended by Alexander Bischofberger (bischofb@informatik.tu-muenchen.de) +// Copyright (c) 1998. +// +// This code may be used in compiled form in any way you desire. This +// file may be redistributed unmodified by any means PROVIDING it is +// not sold for profit without the authors written consent, and +// providing that this notice and the authors name is included. If +// the source code in this file is used in any commercial application +// then a simple email would be nice. +// +// This file is provided "as is" with no expressed or implied warranty. +// The author accepts no liability if it causes any damage whatsoever. +// It's free - so you get what you pay for. + +#include "ColourPopup.h" + +///////////////////////////////////////////////////////////////////////////// +// CColourPicker window + +void AFXAPI DDX_ColourPicker(CDataExchange *pDX, int nIDC, COLORREF& crColour); + +///////////////////////////////////////////////////////////////////////////// +// CColourPicker window + +#define CP_MODE_TEXT 1 // edit text colour +#define CP_MODE_BK 2 // edit background colour (default) + +class CColourPicker : public CButton +{ +// Construction +public: + CColourPicker(); + DECLARE_DYNCREATE(CColourPicker); + +// Attributes +public: + COLORREF GetColour(); + void SetColour(COLORREF crColour); + + void SetDefaultText(LPCTSTR szDefaultText); + void SetCustomText(LPCTSTR szCustomText); + + void SetTrackSelection(BOOL bTracking = TRUE) { m_bTrackSelection = bTracking; } + BOOL GetTrackSelection() { return m_bTrackSelection; } + + void SetSelectionMode(UINT nMode) { m_nSelectionMode = nMode; } + UINT GetSelectionMode() { return m_nSelectionMode; }; + + void SetBkColour(COLORREF crColourBk); + COLORREF GetBkColour() { return m_crColourBk; } + + void SetTextColour(COLORREF crColourText); + COLORREF GetTextColour() { return m_crColourText;} + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CColourPicker) + public: + virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + protected: + virtual void PreSubclassWindow(); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CColourPicker(); + +protected: + void SetWindowSize(); + +// protected attributes +protected: + BOOL m_bActive, // Is the dropdown active? + m_bTrackSelection; // track colour changes? + COLORREF m_crColourBk; + COLORREF m_crColourText; + UINT m_nSelectionMode; + CRect m_ArrowRect; + CString m_strDefaultText; + CString m_strCustomText; + + // Generated message map functions +protected: + //{{AFX_MSG(CColourPicker) + afx_msg BOOL OnClicked(); + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + //}}AFX_MSG + afx_msg LONG OnSelEndOK(UINT lParam, LONG wParam); + afx_msg LONG OnSelEndCancel(UINT lParam, LONG wParam); + afx_msg LONG OnSelChange(UINT lParam, LONG wParam); + + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_COLOURPICKER_H__D0B75901_9830_11D1_9C0F_00A0243D1382__INCLUDED_) diff --git a/ChartDemo/ColourPicker/ColourPopup.cpp b/ChartDemo/ColourPicker/ColourPopup.cpp new file mode 100644 index 0000000..9a9c06f --- /dev/null +++ b/ChartDemo/ColourPicker/ColourPopup.cpp @@ -0,0 +1,917 @@ +// ColourPopup.cpp : implementation file +// +// Written by Chris Maunder (chrismaunder@codeguru.com) +// Extended by Alexander Bischofberger (bischofb@informatik.tu-muenchen.de) +// Copyright (c) 1998. +// +// Updated 30 May 1998 to allow any number of colours, and to +// make the appearance closer to Office 97. +// Also added "Default" text area. (CJM) +// +// 13 June 1998 Fixed change of focus bug (CJM) +// 30 June 1998 Fixed bug caused by focus bug fix (D'oh!!) +// Solution suggested by Paul Wilkerson. +// +// ColourPopup is a helper class for the colour picker control +// CColourPicker. Check out the header file or the accompanying +// HTML doc file for details. +// +// This code may be used in compiled form in any way you desire. This +// file may be redistributed unmodified by any means PROVIDING it is +// not sold for profit without the authors written consent, and +// providing that this notice and the authors name is included. +// +// This file is provided "as is" with no expressed or implied warranty. +// The author accepts no liability if it causes any damage to you or your +// computer whatsoever. It's free, so don't hassle me about it. +// +// Expect bugs. +// +// Please use and enjoy. Please let me know of any bugs/mods/improvements +// that you have found/implemented and I will fix/incorporate them into this +// file. + +#include "stdafx.h" +#include +#include "ColourPicker.h" +#include "ColourPopup.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +#define DEFAULT_BOX_VALUE -3 +#define CUSTOM_BOX_VALUE -2 +#define INVALID_COLOUR -1 + +#define MAX_COLOURS 100 + + +ColourTableEntry CColourPopup::m_crColours[] = +{ + { RGB(0x00, 0x00, 0x00), _T("Black") }, + { RGB(0xA5, 0x2A, 0x00), _T("Brown") }, + { RGB(0x00, 0x40, 0x40), _T("Dark Olive Green") }, + { RGB(0x00, 0x55, 0x00), _T("Dark Green") }, + { RGB(0x00, 0x00, 0x5E), _T("Dark Teal") }, + { RGB(0x00, 0x00, 0x8B), _T("Dark blue") }, + { RGB(0x4B, 0x00, 0x82), _T("Indigo") }, + { RGB(0x28, 0x28, 0x28), _T("Dark grey") }, + + { RGB(0x8B, 0x00, 0x00), _T("Dark red") }, + { RGB(0xFF, 0x68, 0x20), _T("Orange") }, + { RGB(0x8B, 0x8B, 0x00), _T("Dark yellow") }, + { RGB(0x00, 0x93, 0x00), _T("Green") }, + { RGB(0x38, 0x8E, 0x8E), _T("Teal") }, + { RGB(0x00, 0x00, 0xFF), _T("Blue") }, + { RGB(0x7B, 0x7B, 0xC0), _T("Blue-grey") }, + { RGB(0x66, 0x66, 0x66), _T("Grey - 40") }, + + { RGB(0xFF, 0x00, 0x00), _T("Red") }, + { RGB(0xFF, 0xAD, 0x5B), _T("Light orange") }, + { RGB(0x32, 0xCD, 0x32), _T("Lime") }, + { RGB(0x3C, 0xB3, 0x71), _T("Sea green") }, + { RGB(0x7F, 0xFF, 0xD4), _T("Aqua") }, + { RGB(0x7D, 0x9E, 0xC0), _T("Light blue") }, + { RGB(0x80, 0x00, 0x80), _T("Violet") }, + { RGB(0x7F, 0x7F, 0x7F), _T("Grey - 50") }, + + { RGB(0xFF, 0xC0, 0xCB), _T("Pink") }, + { RGB(0xFF, 0xD7, 0x00), _T("Gold") }, + { RGB(0xFF, 0xFF, 0x00), _T("Yellow") }, + { RGB(0x00, 0xFF, 0x00), _T("Bright green") }, + { RGB(0x40, 0xE0, 0xD0), _T("Turquoise") }, + { RGB(0xC0, 0xFF, 0xFF), _T("Skyblue") }, + { RGB(0x48, 0x00, 0x48), _T("Plum") }, + { RGB(0xC0, 0xC0, 0xC0), _T("Light grey") }, + + { RGB(0xFF, 0xE4, 0xE1), _T("Rose") }, + { RGB(0xD2, 0xB4, 0x8C), _T("Tan") }, + { RGB(0xFF, 0xFF, 0xE0), _T("Light yellow") }, + { RGB(0x98, 0xFB, 0x98), _T("Pale green ") }, + { RGB(0xAF, 0xEE, 0xEE), _T("Pale turquoise") }, + { RGB(0x68, 0x83, 0x8B), _T("Pale blue") }, + { RGB(0xE6, 0xE6, 0xFA), _T("Lavender") }, + { RGB(0xFF, 0xFF, 0xFF), _T("White") } +}; + +///////////////////////////////////////////////////////////////////////////// +// CColourPopup + +CColourPopup::CColourPopup() +{ + Initialise(); +} + +CColourPopup::CColourPopup(CPoint p, COLORREF crColour, CWnd* pParentWnd, + LPCTSTR szDefaultText /* = NULL */, + LPCTSTR szCustomText /* = NULL */) +{ + Initialise(); + + m_crColour = m_crInitialColour = crColour; + m_pParent = pParentWnd; + m_strDefaultText = (szDefaultText)? szDefaultText : _T(""); + m_strCustomText = (szCustomText)? szCustomText : _T(""); + + CColourPopup::Create(p, crColour, pParentWnd, szDefaultText, szCustomText); +} + +void CColourPopup::Initialise() +{ + m_nNumColours = sizeof(m_crColours)/sizeof(ColourTableEntry); + ASSERT(m_nNumColours <= MAX_COLOURS); + if (m_nNumColours > MAX_COLOURS) + m_nNumColours = MAX_COLOURS; + + m_nNumColumns = 0; + m_nNumRows = 0; + m_nBoxSize = 18; + m_nMargin = ::GetSystemMetrics(SM_CXEDGE); + m_nCurrentSel = INVALID_COLOUR; + m_nChosenColourSel = INVALID_COLOUR; + m_pParent = NULL; + m_crColour = m_crInitialColour = RGB(0,0,0); + + m_bChildWindowVisible = FALSE; + + // Idiot check: Make sure the colour square is at least 5 x 5; + if (m_nBoxSize - 2*m_nMargin - 2 < 5) m_nBoxSize = 5 + 2*m_nMargin + 2; + + // Create the font + NONCLIENTMETRICS ncm; + ncm.cbSize = sizeof(NONCLIENTMETRICS); + VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0)); + m_Font.CreateFontIndirect(&(ncm.lfMessageFont)); + + // Create the palette + struct { + LOGPALETTE LogPalette; + PALETTEENTRY PalEntry[MAX_COLOURS]; + } pal; + + LOGPALETTE* pLogPalette = (LOGPALETTE*) &pal; + pLogPalette->palVersion = 0x300; + pLogPalette->palNumEntries = (WORD) m_nNumColours; + + for (int i = 0; i < m_nNumColours; i++) + { + pLogPalette->palPalEntry[i].peRed = GetRValue(m_crColours[i].crColour); + pLogPalette->palPalEntry[i].peGreen = GetGValue(m_crColours[i].crColour); + pLogPalette->palPalEntry[i].peBlue = GetBValue(m_crColours[i].crColour); + pLogPalette->palPalEntry[i].peFlags = 0; + } + + m_Palette.CreatePalette(pLogPalette); +} + +CColourPopup::~CColourPopup() +{ + m_Font.DeleteObject(); + m_Palette.DeleteObject(); +} + +BOOL CColourPopup::Create(CPoint p, COLORREF crColour, CWnd* pParentWnd, + LPCTSTR szDefaultText /* = NULL */, + LPCTSTR szCustomText /* = NULL */) +{ + ASSERT(pParentWnd && ::IsWindow(pParentWnd->GetSafeHwnd())); + ASSERT(pParentWnd->IsKindOf(RUNTIME_CLASS(CColourPicker))); + + m_pParent = pParentWnd; + m_crColour = m_crInitialColour = crColour; + + // Get the class name and create the window + CString szClassName = AfxRegisterWndClass(CS_CLASSDC|CS_SAVEBITS|CS_HREDRAW|CS_VREDRAW, + 0, + (HBRUSH) (COLOR_BTNFACE+1), + 0); + + if (!CWnd::CreateEx(0, szClassName, _T(""), WS_VISIBLE|WS_POPUP, + p.x, p.y, 100, 100, // size updated soon + pParentWnd->GetSafeHwnd(), 0, NULL)) + return FALSE; + + // Store the Custom text + if (szCustomText != NULL) + m_strCustomText = szCustomText; + + // Store the Default Area text + if (szDefaultText != NULL) + m_strDefaultText = szDefaultText; + + // Set the window size + SetWindowSize(); + + // Create the tooltips + CreateToolTips(); + + // Find which cell (if any) corresponds to the initial colour + FindCellFromColour(crColour); + + // Capture all mouse events for the life of this window + SetCapture(); + + return TRUE; +} + +BEGIN_MESSAGE_MAP(CColourPopup, CWnd) + //{{AFX_MSG_MAP(CColourPopup) + ON_WM_NCDESTROY() + ON_WM_LBUTTONUP() + ON_WM_PAINT() + ON_WM_MOUSEMOVE() + ON_WM_KEYDOWN() + ON_WM_QUERYNEWPALETTE() + ON_WM_PALETTECHANGED() + ON_WM_KILLFOCUS() + ON_WM_ACTIVATEAPP() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CColourPopup message handlers + +// For tooltips +BOOL CColourPopup::PreTranslateMessage(MSG* pMsg) +{ + m_ToolTip.RelayEvent(pMsg); + + // Fix (Adrian Roman): Sometimes if the picker loses focus it is never destroyed + if (GetCapture()->GetSafeHwnd() != m_hWnd) + SetCapture(); + + return CWnd::PreTranslateMessage(pMsg); +} + +// If an arrow key is pressed, then move the selection +void CColourPopup::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + int row = GetRow(m_nCurrentSel), + col = GetColumn(m_nCurrentSel); + + if (nChar == VK_DOWN) + { + if (row == DEFAULT_BOX_VALUE) + row = col = 0; + else if (row == CUSTOM_BOX_VALUE) + { + if (m_strDefaultText.GetLength()) + row = col = DEFAULT_BOX_VALUE; + else + row = col = 0; + } + else + { + row++; + if (GetIndex(row,col) < 0) + { + if (m_strCustomText.GetLength()) + row = col = CUSTOM_BOX_VALUE; + else if (m_strDefaultText.GetLength()) + row = col = DEFAULT_BOX_VALUE; + else + row = col = 0; + } + } + ChangeSelection(GetIndex(row, col)); + } + + if (nChar == VK_UP) + { + if (row == DEFAULT_BOX_VALUE) + { + if (m_strCustomText.GetLength()) + row = col = CUSTOM_BOX_VALUE; + else + { + row = GetRow(m_nNumColours-1); + col = GetColumn(m_nNumColours-1); + } + } + else if (row == CUSTOM_BOX_VALUE) + { + row = GetRow(m_nNumColours-1); + col = GetColumn(m_nNumColours-1); + } + else if (row > 0) row--; + else /* row == 0 */ + { + if (m_strDefaultText.GetLength()) + row = col = DEFAULT_BOX_VALUE; + else if (m_strCustomText.GetLength()) + row = col = CUSTOM_BOX_VALUE; + else + { + row = GetRow(m_nNumColours-1); + col = GetColumn(m_nNumColours-1); + } + } + ChangeSelection(GetIndex(row, col)); + } + + if (nChar == VK_RIGHT) + { + if (row == DEFAULT_BOX_VALUE) + row = col = 0; + else if (row == CUSTOM_BOX_VALUE) + { + if (m_strDefaultText.GetLength()) + row = col = DEFAULT_BOX_VALUE; + else + row = col = 0; + } + else if (col < m_nNumColumns-1) + col++; + else + { + col = 0; row++; + } + + if (GetIndex(row,col) == INVALID_COLOUR) + { + if (m_strCustomText.GetLength()) + row = col = CUSTOM_BOX_VALUE; + else if (m_strDefaultText.GetLength()) + row = col = DEFAULT_BOX_VALUE; + else + row = col = 0; + } + + ChangeSelection(GetIndex(row, col)); + } + + if (nChar == VK_LEFT) + { + if (row == DEFAULT_BOX_VALUE) + { + if (m_strCustomText.GetLength()) + row = col = CUSTOM_BOX_VALUE; + else + { + row = GetRow(m_nNumColours-1); + col = GetColumn(m_nNumColours-1); + } + } + else if (row == CUSTOM_BOX_VALUE) + { + row = GetRow(m_nNumColours-1); + col = GetColumn(m_nNumColours-1); + } + else if (col > 0) col--; + else /* col == 0 */ + { + if (row > 0) { row--; col = m_nNumColumns-1; } + else + { + if (m_strDefaultText.GetLength()) + row = col = DEFAULT_BOX_VALUE; + else if (m_strCustomText.GetLength()) + row = col = CUSTOM_BOX_VALUE; + else + { + row = GetRow(m_nNumColours-1); + col = GetColumn(m_nNumColours-1); + } + } + } + ChangeSelection(GetIndex(row, col)); + } + + if (nChar == VK_ESCAPE) + { + m_crColour = m_crInitialColour; + EndSelection(CPN_SELENDCANCEL); + return; + } + + if (nChar == VK_RETURN || nChar == VK_SPACE) + { + EndSelection(CPN_SELENDOK); + return; + } + + CWnd::OnKeyDown(nChar, nRepCnt, nFlags); +} + +// auto-deletion +void CColourPopup::OnNcDestroy() +{ + CWnd::OnNcDestroy(); + delete this; +} + +void CColourPopup::OnPaint() +{ + CPaintDC dc(this); // device context for painting + + // Draw the Default Area text + if (m_strDefaultText.GetLength()) + DrawCell(&dc, DEFAULT_BOX_VALUE); + + // Draw colour cells + for (int i = 0; i < m_nNumColours; i++) + DrawCell(&dc, i); + + // Draw custom text + if (m_strCustomText.GetLength()) + DrawCell(&dc, CUSTOM_BOX_VALUE); + + // Draw raised window edge (ex-window style WS_EX_WINDOWEDGE is sposed to do this, + // but for some reason isn't + CRect rect; + GetClientRect(rect); + dc.DrawEdge(rect, EDGE_RAISED, BF_RECT); +} + +void CColourPopup::OnMouseMove(UINT nFlags, CPoint point) +{ + int nNewSelection = INVALID_COLOUR; + + // Translate points to be relative raised window edge + point.x -= m_nMargin; + point.y -= m_nMargin; + + // First check we aren't in text box + if (m_strCustomText.GetLength() && m_CustomTextRect.PtInRect(point)) + nNewSelection = CUSTOM_BOX_VALUE; + else if (m_strDefaultText.GetLength() && m_DefaultTextRect.PtInRect(point)) + nNewSelection = DEFAULT_BOX_VALUE; + else + { + // Take into account text box + if (m_strDefaultText.GetLength()) + point.y -= m_DefaultTextRect.Height(); + + // Get the row and column + nNewSelection = GetIndex(point.y / m_nBoxSize, point.x / m_nBoxSize); + + // In range? If not, default and exit + if (nNewSelection < 0 || nNewSelection >= m_nNumColours) + { + CWnd::OnMouseMove(nFlags, point); + return; + } + } + + // OK - we have the row and column of the current selection (may be CUSTOM_BOX_VALUE) + // Has the row/col selection changed? If yes, then redraw old and new cells. + if (nNewSelection != m_nCurrentSel) + ChangeSelection(nNewSelection); + + CWnd::OnMouseMove(nFlags, point); +} + +// End selection on LButtonUp +void CColourPopup::OnLButtonUp(UINT nFlags, CPoint point) +{ + CWnd::OnLButtonUp(nFlags, point); + + DWORD pos = GetMessagePos(); + point = CPoint(LOWORD(pos), HIWORD(pos)); + + if (m_WindowRect.PtInRect(point)) + EndSelection(CPN_SELENDOK); + else + EndSelection(CPN_SELENDCANCEL); +} + +///////////////////////////////////////////////////////////////////////////// +// CColourPopup implementation + +int CColourPopup::GetIndex(int row, int col) const +{ + if ((row == CUSTOM_BOX_VALUE || col == CUSTOM_BOX_VALUE) && m_strCustomText.GetLength()) + return CUSTOM_BOX_VALUE; + else if ((row == DEFAULT_BOX_VALUE || col == DEFAULT_BOX_VALUE) && m_strDefaultText.GetLength()) + return DEFAULT_BOX_VALUE; + else if (row < 0 || col < 0 || row >= m_nNumRows || col >= m_nNumColumns) + return INVALID_COLOUR; + else + { + if (row*m_nNumColumns + col >= m_nNumColours) + return INVALID_COLOUR; + else + return row*m_nNumColumns + col; + } +} + +int CColourPopup::GetRow(int nIndex) const +{ + if (nIndex == CUSTOM_BOX_VALUE && m_strCustomText.GetLength()) + return CUSTOM_BOX_VALUE; + else if (nIndex == DEFAULT_BOX_VALUE && m_strDefaultText.GetLength()) + return DEFAULT_BOX_VALUE; + else if (nIndex < 0 || nIndex >= m_nNumColours) + return INVALID_COLOUR; + else + return nIndex / m_nNumColumns; +} + +int CColourPopup::GetColumn(int nIndex) const +{ + if (nIndex == CUSTOM_BOX_VALUE && m_strCustomText.GetLength()) + return CUSTOM_BOX_VALUE; + else if (nIndex == DEFAULT_BOX_VALUE && m_strDefaultText.GetLength()) + return DEFAULT_BOX_VALUE; + else if (nIndex < 0 || nIndex >= m_nNumColours) + return INVALID_COLOUR; + else + return nIndex % m_nNumColumns; +} + +void CColourPopup::FindCellFromColour(COLORREF crColour) +{ + if (crColour == CLR_DEFAULT && m_strDefaultText.GetLength()) + { + m_nChosenColourSel = DEFAULT_BOX_VALUE; + return; + } + + for (int i = 0; i < m_nNumColours; i++) + { + if (GetColour(i) == crColour) + { + m_nChosenColourSel = i; + return; + } + } + + if (m_strCustomText.GetLength()) + m_nChosenColourSel = CUSTOM_BOX_VALUE; + else + m_nChosenColourSel = INVALID_COLOUR; +} + +// Gets the dimensions of the colour cell given by (row,col) +BOOL CColourPopup::GetCellRect(int nIndex, const LPRECT& rect) +{ + if (nIndex == CUSTOM_BOX_VALUE) + { + ::SetRect(rect, + m_CustomTextRect.left, m_CustomTextRect.top, + m_CustomTextRect.right, m_CustomTextRect.bottom); + return TRUE; + } + else if (nIndex == DEFAULT_BOX_VALUE) + { + ::SetRect(rect, + m_DefaultTextRect.left, m_DefaultTextRect.top, + m_DefaultTextRect.right, m_DefaultTextRect.bottom); + return TRUE; + } + + if (nIndex < 0 || nIndex >= m_nNumColours) + return FALSE; + + rect->left = GetColumn(nIndex) * m_nBoxSize + m_nMargin; + rect->top = GetRow(nIndex) * m_nBoxSize + m_nMargin; + + // Move everything down if we are displaying a default text area + if (m_strDefaultText.GetLength()) + rect->top += (m_nMargin + m_DefaultTextRect.Height()); + + rect->right = rect->left + m_nBoxSize; + rect->bottom = rect->top + m_nBoxSize; + + return TRUE; +} + +// Works out an appropriate size and position of this window +void CColourPopup::SetWindowSize() +{ + CSize TextSize; + + // If we are showing a custom or default text area, get the font and text size. + if (m_strCustomText.GetLength() || m_strDefaultText.GetLength()) + { + CClientDC dc(this); + CFont* pOldFont = (CFont*) dc.SelectObject(&m_Font); + + // Get the size of the custom text (if there IS custom text) + TextSize = CSize(0,0); + if (m_strCustomText.GetLength()) + TextSize = dc.GetTextExtent(m_strCustomText); + + // Get the size of the default text (if there IS default text) + if (m_strDefaultText.GetLength()) + { + CSize DefaultSize = dc.GetTextExtent(m_strDefaultText); + if (DefaultSize.cx > TextSize.cx) TextSize.cx = DefaultSize.cx; + if (DefaultSize.cy > TextSize.cy) TextSize.cy = DefaultSize.cy; + } + + dc.SelectObject(pOldFont); + TextSize += CSize(2*m_nMargin,2*m_nMargin); + + // Add even more space to draw the horizontal line + TextSize.cy += 2*m_nMargin + 2; + } + + // Get the number of columns and rows + //m_nNumColumns = (int) sqrt((double)m_nNumColours); // for a square window (yuk) + m_nNumColumns = 8; + m_nNumRows = m_nNumColours / m_nNumColumns; + if (m_nNumColours % m_nNumColumns) m_nNumRows++; + + // Get the current window position, and set the new size + CRect rect; + GetWindowRect(rect); + + m_WindowRect.SetRect(rect.left, rect.top, + rect.left + m_nNumColumns*m_nBoxSize + 2*m_nMargin, + rect.top + m_nNumRows*m_nBoxSize + 2*m_nMargin); + + // if custom text, then expand window if necessary, and set text width as + // window width + if (m_strDefaultText.GetLength()) + { + if (TextSize.cx > m_WindowRect.Width()) + m_WindowRect.right = m_WindowRect.left + TextSize.cx; + TextSize.cx = m_WindowRect.Width()-2*m_nMargin; + + // Work out the text area + m_DefaultTextRect.SetRect(m_nMargin, m_nMargin, + m_nMargin+TextSize.cx, 2*m_nMargin+TextSize.cy); + m_WindowRect.bottom += m_DefaultTextRect.Height() + 2*m_nMargin; + } + + // if custom text, then expand window if necessary, and set text width as + // window width + if (m_strCustomText.GetLength()) + { + if (TextSize.cx > m_WindowRect.Width()) + m_WindowRect.right = m_WindowRect.left + TextSize.cx; + TextSize.cx = m_WindowRect.Width()-2*m_nMargin; + + // Work out the text area + m_CustomTextRect.SetRect(m_nMargin, m_WindowRect.Height(), + m_nMargin+TextSize.cx, + m_WindowRect.Height()+m_nMargin+TextSize.cy); + m_WindowRect.bottom += m_CustomTextRect.Height() + 2*m_nMargin; + } + + // Need to check it'll fit on screen: Too far right? + CSize ScreenSize(::GetSystemMetrics(SM_CXSCREEN), ::GetSystemMetrics(SM_CYSCREEN)); + if (m_WindowRect.right > ScreenSize.cx) + m_WindowRect.OffsetRect(-(m_WindowRect.right - ScreenSize.cx), 0); + + // Too far left? + if (m_WindowRect.left < 0) + m_WindowRect.OffsetRect( -m_WindowRect.left, 0); + + // Bottom falling out of screen? + if (m_WindowRect.bottom > ScreenSize.cy) + { + CRect ParentRect; + m_pParent->GetWindowRect(ParentRect); + m_WindowRect.OffsetRect(0, -(ParentRect.Height() + m_WindowRect.Height())); + } + + // Set the window size and position + MoveWindow(m_WindowRect, TRUE); +} + +void CColourPopup::CreateToolTips() +{ + // Create the tool tip + if (!m_ToolTip.Create(this)) return; + + // Add a tool for each cell + for (int i = 0; i < m_nNumColours; i++) + { + CRect rect; + if (!GetCellRect(i, rect)) continue; + m_ToolTip.AddTool(this, GetColourName(i), rect, 1); + } +} + +void CColourPopup::ChangeSelection(int nIndex) +{ + CClientDC dc(this); // device context for drawing + + if (nIndex > m_nNumColours) + nIndex = CUSTOM_BOX_VALUE; + + if ((m_nCurrentSel >= 0 && m_nCurrentSel < m_nNumColours) || + m_nCurrentSel == CUSTOM_BOX_VALUE || m_nCurrentSel == DEFAULT_BOX_VALUE) + { + // Set Current selection as invalid and redraw old selection (this way + // the old selection will be drawn unselected) + int OldSel = m_nCurrentSel; + m_nCurrentSel = INVALID_COLOUR; + DrawCell(&dc, OldSel); + } + + // Set the current selection as row/col and draw (it will be drawn selected) + m_nCurrentSel = nIndex; + DrawCell(&dc, m_nCurrentSel); + + // Store the current colour + if (m_nCurrentSel == CUSTOM_BOX_VALUE) + m_pParent->SendMessage(CPN_SELCHANGE, (WPARAM) m_crInitialColour, 0); + else if (m_nCurrentSel == DEFAULT_BOX_VALUE) + { + m_crColour = CLR_DEFAULT; + m_pParent->SendMessage(CPN_SELCHANGE, (WPARAM) CLR_DEFAULT, 0); + } + else + { + m_crColour = GetColour(m_nCurrentSel); + m_pParent->SendMessage(CPN_SELCHANGE, (WPARAM) m_crColour, 0); + } +} + +void CColourPopup::EndSelection(int nMessage) +{ + ReleaseCapture(); + + // If custom text selected, perform a custom colour selection + if (nMessage != CPN_SELENDCANCEL && m_nCurrentSel == CUSTOM_BOX_VALUE) + { + m_bChildWindowVisible = TRUE; + + CColorDialog dlg(m_crInitialColour, CC_FULLOPEN | CC_ANYCOLOR, this); + + if (dlg.DoModal() == IDOK) + m_crColour = dlg.GetColor(); + else + nMessage = CPN_SELENDCANCEL; + + m_bChildWindowVisible = FALSE; + } + + if (nMessage == CPN_SELENDCANCEL) + m_crColour = m_crInitialColour; + + m_pParent->SendMessage(nMessage, (WPARAM) m_crColour, 0); + + // Kill focus bug fixed by Martin Wawrusch + if (!m_bChildWindowVisible) + DestroyWindow(); +} + +void CColourPopup::DrawCell(CDC* pDC, int nIndex) +{ + // For the Custom Text area + if (m_strCustomText.GetLength() && nIndex == CUSTOM_BOX_VALUE) + { + // The extent of the actual text button + CRect TextButtonRect = m_CustomTextRect; + TextButtonRect.top += 2*m_nMargin; + + // Fill background + pDC->FillSolidRect(TextButtonRect, ::GetSysColor(COLOR_3DFACE)); + + // Draw horizontal line + pDC->FillSolidRect(m_CustomTextRect.left+2*m_nMargin, m_CustomTextRect.top, + m_CustomTextRect.Width()-4*m_nMargin, 1, ::GetSysColor(COLOR_3DSHADOW)); + pDC->FillSolidRect(m_CustomTextRect.left+2*m_nMargin, m_CustomTextRect.top+1, + m_CustomTextRect.Width()-4*m_nMargin, 1, ::GetSysColor(COLOR_3DHILIGHT)); + + TextButtonRect.DeflateRect(1,1); + + // fill background + if (m_nChosenColourSel == nIndex && m_nCurrentSel != nIndex) + pDC->FillSolidRect(TextButtonRect, ::GetSysColor(COLOR_3DLIGHT)); + else + pDC->FillSolidRect(TextButtonRect, ::GetSysColor(COLOR_3DFACE)); + + // Draw button + if (m_nCurrentSel == nIndex) + pDC->DrawEdge(TextButtonRect, BDR_RAISEDINNER, BF_RECT); + else if (m_nChosenColourSel == nIndex) + pDC->DrawEdge(TextButtonRect, BDR_SUNKENOUTER, BF_RECT); + + // Draw custom text + CFont *pOldFont = (CFont*) pDC->SelectObject(&m_Font); + pDC->SetBkMode(TRANSPARENT); + pDC->DrawText(m_strCustomText, TextButtonRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + pDC->SelectObject(pOldFont); + + return; + } + + // For the Default Text area + if (m_strDefaultText.GetLength() && nIndex == DEFAULT_BOX_VALUE) + { + // Fill background + pDC->FillSolidRect(m_DefaultTextRect, ::GetSysColor(COLOR_3DFACE)); + + // The extent of the actual text button + CRect TextButtonRect = m_DefaultTextRect; + TextButtonRect.DeflateRect(1,1); + + // fill background + if (m_nChosenColourSel == nIndex && m_nCurrentSel != nIndex) + pDC->FillSolidRect(TextButtonRect, ::GetSysColor(COLOR_3DLIGHT)); + else + pDC->FillSolidRect(TextButtonRect, ::GetSysColor(COLOR_3DFACE)); + + // Draw thin line around text + CRect LineRect = TextButtonRect; + LineRect.DeflateRect(2*m_nMargin,2*m_nMargin); + CPen pen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW)); + CPen* pOldPen = pDC->SelectObject(&pen); + pDC->SelectStockObject(NULL_BRUSH); + pDC->Rectangle(LineRect); + pDC->SelectObject(pOldPen); + + // Draw button + if (m_nCurrentSel == nIndex) + pDC->DrawEdge(TextButtonRect, BDR_RAISEDINNER, BF_RECT); + else if (m_nChosenColourSel == nIndex) + pDC->DrawEdge(TextButtonRect, BDR_SUNKENOUTER, BF_RECT); + + // Draw custom text + CFont *pOldFont = (CFont*) pDC->SelectObject(&m_Font); + pDC->SetBkMode(TRANSPARENT); + pDC->DrawText(m_strDefaultText, TextButtonRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + pDC->SelectObject(pOldFont); + + return; + } + + CRect rect; + if (!GetCellRect(nIndex, rect)) return; + + // Select and realize the palette + CPalette* pOldPalette = NULL; + if (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) + { + pOldPalette = pDC->SelectPalette(&m_Palette, FALSE); + pDC->RealizePalette(); + } + + // fill background + if (m_nChosenColourSel == nIndex && m_nCurrentSel != nIndex) + pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DHILIGHT)); + else + pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE)); + + // Draw button + if (m_nCurrentSel == nIndex) + pDC->DrawEdge(rect, BDR_RAISEDINNER, BF_RECT); + else if (m_nChosenColourSel == nIndex) + pDC->DrawEdge(rect, BDR_SUNKENOUTER, BF_RECT); + + CBrush brush(PALETTERGB(GetRValue(GetColour(nIndex)), + GetGValue(GetColour(nIndex)), + GetBValue(GetColour(nIndex)) )); + CPen pen; + pen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW)); + + CBrush* pOldBrush = (CBrush*) pDC->SelectObject(&brush); + CPen* pOldPen = (CPen*) pDC->SelectObject(&pen); + + // Draw the cell colour + rect.DeflateRect(m_nMargin+1, m_nMargin+1); + pDC->Rectangle(rect); + + // restore DC and cleanup + pDC->SelectObject(pOldBrush); + pDC->SelectObject(pOldPen); + brush.DeleteObject(); + pen.DeleteObject(); + + if (pOldPalette && pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) + pDC->SelectPalette(pOldPalette, FALSE); +} + +BOOL CColourPopup::OnQueryNewPalette() +{ + Invalidate(); + return CWnd::OnQueryNewPalette(); +} + +void CColourPopup::OnPaletteChanged(CWnd* pFocusWnd) +{ + CWnd::OnPaletteChanged(pFocusWnd); + + if (pFocusWnd->GetSafeHwnd() != GetSafeHwnd()) + Invalidate(); +} + +void CColourPopup::OnKillFocus(CWnd* pNewWnd) +{ + CWnd::OnKillFocus(pNewWnd); + + ReleaseCapture(); + //DestroyWindow(); - causes crash when Custom colour dialog appears. +} + +// KillFocus problem fix suggested by Paul Wilkerson. +#if _MFC_VER < 0x0700 + void CColourPopup::OnActivateApp(BOOL bActive, HTASK hTask) +#else + void CColourPopup::OnActivateApp(BOOL bActive, DWORD hTask) +#endif +{ + CWnd::OnActivateApp(bActive, hTask); + + // If Deactivating App, cancel this selection + if (!bActive) + EndSelection(CPN_SELENDCANCEL); +} diff --git a/ChartDemo/ColourPicker/ColourPopup.h b/ChartDemo/ColourPicker/ColourPopup.h new file mode 100644 index 0000000..3d738a5 --- /dev/null +++ b/ChartDemo/ColourPicker/ColourPopup.h @@ -0,0 +1,132 @@ +#if !defined(AFX_COLOURPOPUP_H__D0B75902_9830_11D1_9C0F_00A0243D1382__INCLUDED_) +#define AFX_COLOURPOPUP_H__D0B75902_9830_11D1_9C0F_00A0243D1382__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +// ColourPopup.h : header file +// +// Written by Chris Maunder (chrismaunder@codeguru.com) +// Extended by Alexander Bischofberger (bischofb@informatik.tu-muenchen.de) +// Copyright (c) 1998. +// +// This code may be used in compiled form in any way you desire. This +// file may be redistributed unmodified by any means PROVIDING it is +// not sold for profit without the authors written consent, and +// providing that this notice and the authors name is included. If +// the source code in this file is used in any commercial application +// then a simple email would be nice. +// +// This file is provided "as is" with no expressed or implied warranty. +// The author accepts no liability if it causes any damage whatsoever. +// It's free - so you get what you pay for. + + +// CColourPopup messages +#define CPN_SELCHANGE WM_USER + 1001 // Colour Picker Selection change +#define CPN_DROPDOWN WM_USER + 1002 // Colour Picker drop down +#define CPN_CLOSEUP WM_USER + 1003 // Colour Picker close up +#define CPN_SELENDOK WM_USER + 1004 // Colour Picker end OK +#define CPN_SELENDCANCEL WM_USER + 1005 // Colour Picker end (cancelled) + +// forward declaration +class CColourPicker; + +// To hold the colours and their names +typedef struct { + COLORREF crColour; + TCHAR *szName; +} ColourTableEntry; + +///////////////////////////////////////////////////////////////////////////// +// CColourPopup window + +class CColourPopup : public CWnd +{ +// Construction +public: + CColourPopup(); + CColourPopup(CPoint p, COLORREF crColour, CWnd* pParentWnd, + LPCTSTR szDefaultText = NULL, LPCTSTR szCustomText = NULL); + void Initialise(); + +// Attributes +public: + +// Operations +public: + BOOL Create(CPoint p, COLORREF crColour, CWnd* pParentWnd, + LPCTSTR szDefaultText = NULL, LPCTSTR szCustomText = NULL); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CColourPopup) + public: + virtual BOOL PreTranslateMessage(MSG* pMsg); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CColourPopup(); + +protected: + BOOL GetCellRect(int nIndex, const LPRECT& rect); + void FindCellFromColour(COLORREF crColour); + void SetWindowSize(); + void CreateToolTips(); + void ChangeSelection(int nIndex); + void EndSelection(int nMessage); + void DrawCell(CDC* pDC, int nIndex); + + COLORREF GetColour(int nIndex) { return m_crColours[nIndex].crColour; } + LPCTSTR GetColourName(int nIndex) { return m_crColours[nIndex].szName; } + int GetIndex(int row, int col) const; + int GetRow(int nIndex) const; + int GetColumn(int nIndex) const; + +// protected attributes +protected: + static ColourTableEntry m_crColours[]; + int m_nNumColours; + int m_nNumColumns, m_nNumRows; + int m_nBoxSize, m_nMargin; + int m_nCurrentSel; + int m_nChosenColourSel; + CString m_strDefaultText; + CString m_strCustomText; + CRect m_CustomTextRect, m_DefaultTextRect, m_WindowRect; + CFont m_Font; + CPalette m_Palette; + COLORREF m_crInitialColour, m_crColour; + CToolTipCtrl m_ToolTip; + CWnd* m_pParent; + + BOOL m_bChildWindowVisible; + + // Generated message map functions +protected: + //{{AFX_MSG(CColourPopup) + afx_msg void OnNcDestroy(); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnPaint(); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg BOOL OnQueryNewPalette(); + afx_msg void OnPaletteChanged(CWnd* pFocusWnd); + afx_msg void OnKillFocus(CWnd* pNewWnd); + #if _MFC_VER < 0x0700 + afx_msg void OnActivateApp(BOOL bActive, HTASK hTask); + #else + afx_msg void OnActivateApp(BOOL bActive, DWORD hTask); + #endif + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_COLOURPOPUP_H__D0B75902_9830_11D1_9C0F_00A0243D1382__INCLUDED_) diff --git a/ChartDemo/Doc/html/_chart_axis_8h-source.html b/ChartDemo/Doc/html/_chart_axis_8h-source.html new file mode 100644 index 0000000..8575be8 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_axis_8h-source.html @@ -0,0 +1,265 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartAxis.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_axis_label_8h-source.html b/ChartDemo/Doc/html/_chart_axis_label_8h-source.html new file mode 100644 index 0000000..7a5dfa2 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_axis_label_8h-source.html @@ -0,0 +1,104 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartAxisLabel.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_axis_old_8h-source.html b/ChartDemo/Doc/html/_chart_axis_old_8h-source.html new file mode 100644 index 0000000..bac0169 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_axis_old_8h-source.html @@ -0,0 +1,239 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartAxisOld.h Source File + + + + + +
Generated on Sun Feb 1 14:21:48 2009 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_balloon_label_8h-source.html b/ChartDemo/Doc/html/_chart_balloon_label_8h-source.html new file mode 100644 index 0000000..940289d --- /dev/null +++ b/ChartDemo/Doc/html/_chart_balloon_label_8h-source.html @@ -0,0 +1,95 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartBalloonLabel.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_bar_serie_8h-source.html b/ChartDemo/Doc/html/_chart_bar_serie_8h-source.html new file mode 100644 index 0000000..2d26b5b --- /dev/null +++ b/ChartDemo/Doc/html/_chart_bar_serie_8h-source.html @@ -0,0 +1,148 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartBarSerie.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_candlestick_serie_8h-source.html b/ChartDemo/Doc/html/_chart_candlestick_serie_8h-source.html new file mode 100644 index 0000000..1c5488d --- /dev/null +++ b/ChartDemo/Doc/html/_chart_candlestick_serie_8h-source.html @@ -0,0 +1,110 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartCandlestickSerie.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_cross_hair_cursor_8h-source.html b/ChartDemo/Doc/html/_chart_cross_hair_cursor_8h-source.html new file mode 100644 index 0000000..a69b835 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_cross_hair_cursor_8h-source.html @@ -0,0 +1,77 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartCrossHairCursor.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_ctrl_8h-source.html b/ChartDemo/Doc/html/_chart_ctrl_8h-source.html new file mode 100644 index 0000000..14188e7 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_ctrl_8h-source.html @@ -0,0 +1,305 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartCtrl.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_cursor_8h-source.html b/ChartDemo/Doc/html/_chart_cursor_8h-source.html new file mode 100644 index 0000000..4e156fe --- /dev/null +++ b/ChartDemo/Doc/html/_chart_cursor_8h-source.html @@ -0,0 +1,105 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartCursor.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_date_time_axis_8h-source.html b/ChartDemo/Doc/html/_chart_date_time_axis_8h-source.html new file mode 100644 index 0000000..256154b --- /dev/null +++ b/ChartDemo/Doc/html/_chart_date_time_axis_8h-source.html @@ -0,0 +1,109 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartDateTimeAxis.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_demo_8h-source.html b/ChartDemo/Doc/html/_chart_demo_8h-source.html new file mode 100644 index 0000000..e2a9ca7 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_demo_8h-source.html @@ -0,0 +1,72 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartDemo.h Source File + + + + + +
Generated on Sat Mar 7 11:33:23 2009 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_demo_dlg_8h-source.html b/ChartDemo/Doc/html/_chart_demo_dlg_8h-source.html new file mode 100644 index 0000000..4b0adae --- /dev/null +++ b/ChartDemo/Doc/html/_chart_demo_dlg_8h-source.html @@ -0,0 +1,108 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartDemoDlg.h Source File + + + + + +
Generated on Sat Mar 7 11:33:23 2009 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_drag_line_cursor_8h-source.html b/ChartDemo/Doc/html/_chart_drag_line_cursor_8h-source.html new file mode 100644 index 0000000..d136a6b --- /dev/null +++ b/ChartDemo/Doc/html/_chart_drag_line_cursor_8h-source.html @@ -0,0 +1,81 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartDragLineCursor.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_font_8h-source.html b/ChartDemo/Doc/html/_chart_font_8h-source.html new file mode 100644 index 0000000..5e8349f --- /dev/null +++ b/ChartDemo/Doc/html/_chart_font_8h-source.html @@ -0,0 +1,94 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartFont.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_gantt_serie_8h-source.html b/ChartDemo/Doc/html/_chart_gantt_serie_8h-source.html new file mode 100644 index 0000000..db723e7 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_gantt_serie_8h-source.html @@ -0,0 +1,116 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartGanttSerie.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_gradient_8h-source.html b/ChartDemo/Doc/html/_chart_gradient_8h-source.html new file mode 100644 index 0000000..8b22145 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_gradient_8h-source.html @@ -0,0 +1,69 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartGradient.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_grid_8h-source.html b/ChartDemo/Doc/html/_chart_grid_8h-source.html new file mode 100644 index 0000000..44e2735 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_grid_8h-source.html @@ -0,0 +1,93 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartGrid.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_label_8h-source.html b/ChartDemo/Doc/html/_chart_label_8h-source.html new file mode 100644 index 0000000..0b54b09 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_label_8h-source.html @@ -0,0 +1,104 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartLabel.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_legend_8h-source.html b/ChartDemo/Doc/html/_chart_legend_8h-source.html new file mode 100644 index 0000000..4b4d7e5 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_legend_8h-source.html @@ -0,0 +1,130 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartLegend.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_line_serie_8h-source.html b/ChartDemo/Doc/html/_chart_line_serie_8h-source.html new file mode 100644 index 0000000..729db12 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_line_serie_8h-source.html @@ -0,0 +1,95 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartLineSerie.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_logarithmic_axis_8h-source.html b/ChartDemo/Doc/html/_chart_logarithmic_axis_8h-source.html new file mode 100644 index 0000000..95d897a --- /dev/null +++ b/ChartDemo/Doc/html/_chart_logarithmic_axis_8h-source.html @@ -0,0 +1,82 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartLogarithmicAxis.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_mouse_listener_8h-source.html b/ChartDemo/Doc/html/_chart_mouse_listener_8h-source.html new file mode 100644 index 0000000..b5b6f6a --- /dev/null +++ b/ChartDemo/Doc/html/_chart_mouse_listener_8h-source.html @@ -0,0 +1,83 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartMouseListener.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_object_8h-source.html b/ChartDemo/Doc/html/_chart_object_8h-source.html new file mode 100644 index 0000000..bedcba8 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_object_8h-source.html @@ -0,0 +1,126 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartObject.h Source File + + + + + +
Generated on Sun Feb 1 14:25:46 2009 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_point_label_8h-source.html b/ChartDemo/Doc/html/_chart_point_label_8h-source.html new file mode 100644 index 0000000..fb8cc2d --- /dev/null +++ b/ChartDemo/Doc/html/_chart_point_label_8h-source.html @@ -0,0 +1,107 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartPointLabel.h Source File + + + + + +
Generated on Mon Feb 23 20:14:50 2009 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_points_array_8h-source.html b/ChartDemo/Doc/html/_chart_points_array_8h-source.html new file mode 100644 index 0000000..143e7d1 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_points_array_8h-source.html @@ -0,0 +1,112 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartPointsArray.h Source File + + + + + +
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_points_serie_8h-source.html b/ChartDemo/Doc/html/_chart_points_serie_8h-source.html new file mode 100644 index 0000000..b6d1908 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_points_serie_8h-source.html @@ -0,0 +1,102 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartPointsSerie.h Source File + + + + + +
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_scroll_bar_8h-source.html b/ChartDemo/Doc/html/_chart_scroll_bar_8h-source.html new file mode 100644 index 0000000..d96dca6 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_scroll_bar_8h-source.html @@ -0,0 +1,84 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartScrollBar.h Source File + + + + + +
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_serie_8h-source.html b/ChartDemo/Doc/html/_chart_serie_8h-source.html new file mode 100644 index 0000000..5735ff8 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_serie_8h-source.html @@ -0,0 +1,164 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartSerie.h Source File + + + + + +
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_serie_base_8h-source.html b/ChartDemo/Doc/html/_chart_serie_base_8h-source.html new file mode 100644 index 0000000..72ee6f6 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_serie_base_8h-source.html @@ -0,0 +1,139 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartSerieBase.h Source File + + + + + +
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_series_mouse_listener_8h-source.html b/ChartDemo/Doc/html/_chart_series_mouse_listener_8h-source.html new file mode 100644 index 0000000..a2fcfb7 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_series_mouse_listener_8h-source.html @@ -0,0 +1,72 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartSeriesMouseListener.h Source File + + + + + +
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_standard_axis_8h-source.html b/ChartDemo/Doc/html/_chart_standard_axis_8h-source.html new file mode 100644 index 0000000..f9b7d2d --- /dev/null +++ b/ChartDemo/Doc/html/_chart_standard_axis_8h-source.html @@ -0,0 +1,84 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartStandardAxis.h Source File + + + + + +
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_string_8h-source.html b/ChartDemo/Doc/html/_chart_string_8h-source.html new file mode 100644 index 0000000..b4910b1 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_string_8h-source.html @@ -0,0 +1,60 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartString.h Source File + + + + + +
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_surface_serie_8h-source.html b/ChartDemo/Doc/html/_chart_surface_serie_8h-source.html new file mode 100644 index 0000000..7bf336f --- /dev/null +++ b/ChartDemo/Doc/html/_chart_surface_serie_8h-source.html @@ -0,0 +1,102 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartSurfaceSerie.h Source File + + + + + +
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_title_8h-source.html b/ChartDemo/Doc/html/_chart_title_8h-source.html new file mode 100644 index 0000000..9bdc5e6 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_title_8h-source.html @@ -0,0 +1,109 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartTitle.h Source File + + + + + +
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_chart_x_y_serie_8h-source.html b/ChartDemo/Doc/html/_chart_x_y_serie_8h-source.html new file mode 100644 index 0000000..2e68657 --- /dev/null +++ b/ChartDemo/Doc/html/_chart_x_y_serie_8h-source.html @@ -0,0 +1,115 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/ChartXYSerie.h Source File + + + + + +
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_colour_picker_8h-source.html b/ChartDemo/Doc/html/_colour_picker_8h-source.html new file mode 100644 index 0000000..ea4b0f4 --- /dev/null +++ b/ChartDemo/Doc/html/_colour_picker_8h-source.html @@ -0,0 +1,136 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ColourPicker.h Source File + + + + + +
Generated on Thu Mar 5 21:28:19 2009 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_colour_popup_8h-source.html b/ChartDemo/Doc/html/_colour_popup_8h-source.html new file mode 100644 index 0000000..28e9736 --- /dev/null +++ b/ChartDemo/Doc/html/_colour_popup_8h-source.html @@ -0,0 +1,156 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ColourPopup.h Source File + + + + + +
Generated on Thu Mar 5 21:28:19 2009 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_line_prop_dialog_8h-source.html b/ChartDemo/Doc/html/_line_prop_dialog_8h-source.html new file mode 100644 index 0000000..4dce7a6 --- /dev/null +++ b/ChartDemo/Doc/html/_line_prop_dialog_8h-source.html @@ -0,0 +1,72 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/LinePropDialog.h Source File + + + + + +
Generated on Sat Mar 7 11:33:23 2009 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_points_ordering_8h-source.html b/ChartDemo/Doc/html/_points_ordering_8h-source.html new file mode 100644 index 0000000..4d01559 --- /dev/null +++ b/ChartDemo/Doc/html/_points_ordering_8h-source.html @@ -0,0 +1,56 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/ChartCtrl/PointsOrdering.h Source File + + + + + +
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_points_prop_dialog_8h-source.html b/ChartDemo/Doc/html/_points_prop_dialog_8h-source.html new file mode 100644 index 0000000..7f5f6ec --- /dev/null +++ b/ChartDemo/Doc/html/_points_prop_dialog_8h-source.html @@ -0,0 +1,74 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/PointsPropDialog.h Source File + + + + + +
Generated on Sat Mar 7 11:33:24 2009 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_series_prop_dlg_8h-source.html b/ChartDemo/Doc/html/_series_prop_dlg_8h-source.html new file mode 100644 index 0000000..7c6117b --- /dev/null +++ b/ChartDemo/Doc/html/_series_prop_dlg_8h-source.html @@ -0,0 +1,109 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/SeriesPropDlg.h Source File + + + + + +
Generated on Sat Mar 7 11:33:24 2009 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_std_afx_8h-source.html b/ChartDemo/Doc/html/_std_afx_8h-source.html new file mode 100644 index 0000000..8037869 --- /dev/null +++ b/ChartDemo/Doc/html/_std_afx_8h-source.html @@ -0,0 +1,53 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/StdAfx.h Source File + + + + + +
Generated on Sat Mar 7 11:33:24 2009 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/_surface_prop_dialog_8h-source.html b/ChartDemo/Doc/html/_surface_prop_dialog_8h-source.html new file mode 100644 index 0000000..db462e9 --- /dev/null +++ b/ChartDemo/Doc/html/_surface_prop_dialog_8h-source.html @@ -0,0 +1,72 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/SurfacePropDialog.h Source File + + + + + +
Generated on Sat Mar 7 11:33:24 2009 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/annotated.html b/ChartDemo/Doc/html/annotated.html new file mode 100644 index 0000000..d0dab58 --- /dev/null +++ b/ChartDemo/Doc/html/annotated.html @@ -0,0 +1,67 @@ + + +ChartDemo: Class List + + + + + +
+

Class List

Here are the classes, structs, unions and interfaces with brief descriptions: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CChartAxisBase class that takes care of the management of a chart axis
CChartAxisLabelDraws the label of an axis
CChartBalloonLabel< PointType >Specialization of the CChartLabel to display a balloon label
CChartBarSerieSpecialization of a CChartSerie to display a bars series
CChartCandlestickSerieSpecialization of a CChartSerieBase to display a candlestick series
CChartCrossHairCursorSpecialization of a CChartCursor class for a cross-hair cursor
CChartCtrlThe main chart control class
CChartCursorBase class for cursors which can be added to the chart control
CChartCursorListenerInterface to implement in order to be notified about a cursor movement
CChartDateTimeAxisA specialization of the CChartAxis class for displaying date and time data
CChartDragLineCursorSpecialization of a CChartCursor class for a dragline cursor
CChartFontWrapper class for fonts with advanced properties (italic, bold or underlined)
CChartGanttSerieSpecialization of a CChartSerieBase to display a gantt series
CChartGradientHelper class to draw gradient
CChartGridClass which draws the grid associated with a specific axis
CChartLabel< PointType >Draws a label containing some text which is attached to a point of a series
CChartLabelProvider< PointType >Interface which should be implemented in order to provide text to a label
CChartLegendThis class is responsible for the legend displayed on the control
CChartLineSerieSpecialization of a CChartSerie to display a line series
CChartLogarithmicAxisSpecialization of a CChartAxis to display a logarithmic scale
CChartMouseListenerListener for mouse events occuring on the chart control
CChartPointsArray< T >Manages an array of points which supports fast resizing
CChartPointsSerieSpecialization of a CChartSerie to display a points series
CChartScrollBarClass which manages the interaction with the axis scroll bar
CChartSerieAbstract class that provides a common "interface" for all series in the control
CChartSerieBase< T >Base class for all series of the control
CChartSeriesMouseListener< PointType >Listener for mouse events occuring on a series
CChartStandardAxisSpecialization of a CChartAxis class to display standard values
CChartSurfaceSerieSpecialization of a CChartSerie to display a surface series
CChartTitleThis class is responsible for the titles displayed on the control
CChartXYSerieSpecialization of a CChartSerieBase for series having data with an X and an Y value
SChartCandlestickPointPoint structure used as template parameter for candlestick series
SChartGanttPointPoint structure used as template parameter for gantt series
SChartXYPointStructure containing a point data with X and Y values
+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_axis-members.html b/ChartDemo/Doc/html/class_c_chart_axis-members.html new file mode 100644 index 0000000..39190dc --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_axis-members.html @@ -0,0 +1,98 @@ + + +ChartDemo: Member List + + + + + +
+

CChartAxis Member List

This is the complete list of members for CChartAxis, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CChartAxis()CChartAxis
EAxisAutoModes enum nameCChartAxis
EnableScrollBar(bool bEnabled)CChartAxis
FullAutomatic enum valueCChartAxis
GetAutoHideScrollBar() const CChartAxis
GetAutomaticMode() const CChartAxis [inline]
GetAxisLenght() const CChartAxis [protected]
GetFirstTickValue() const =0CChartAxis [protected, pure virtual]
GetGrid() const CChartAxis [inline]
GetLabel() const CChartAxis [inline]
GetMinMax(double &Minimum, double &Maximum) const CChartAxis [inline]
GetNextTickValue(double dCurrentTick, double &dNextTick) const =0CChartAxis [protected, pure virtual]
GetPosition()CChartAxis
GetScrollbarSteps(int &iTotalSteps, int &iCurrentStep)CChartAxis [protected, virtual]
GetSeriesMinMax(double &Minimum, double &Maximum)CChartAxis [protected]
GetSeriesScreenMinMax(double &Minimum, double &Maximum)CChartAxis [protected]
GetTextColor() const CChartAxis [inline]
GetTickLabel(double TickValue) const =0CChartAxis [protected, pure virtual]
GetTickPos(double Value) const =0CChartAxis [protected, pure virtual]
IsAutomatic() const CChartAxis [inline]
IsHorizontal() const CChartAxis [inline]
IsInverted() const CChartAxis [inline]
IsPointInside(const CPoint &screenPoint) const CChartAxis
IsVisible() const CChartAxis [inline]
m_AutoModeCChartAxis [protected]
m_AxisRectCChartAxis [protected]
m_bAutoTicksCChartAxis [protected]
m_bDiscreteCChartAxis [protected]
m_bIsHorizontalCChartAxis [protected]
m_bIsInvertedCChartAxis [protected]
m_bIsSecondaryCChartAxis [protected]
m_bIsVisibleCChartAxis [protected]
m_EndPosCChartAxis [protected]
m_MaxValueCChartAxis [protected]
m_MinValueCChartAxis [protected]
m_pParentCtrlCChartAxis [protected]
m_StartPosCChartAxis [protected]
m_UnzoomMaxCChartAxis [protected]
m_UnzoomMinCChartAxis [protected]
NotAutomatic enum valueCChartAxis
PanAxis(long PanStart, long PanEnd)CChartAxis [protected, virtual]
RefreshFirstTick()=0CChartAxis [protected, pure virtual]
RefreshTickIncrement()=0CChartAxis [protected, pure virtual]
ScreenAutomatic enum valueCChartAxis
ScreenToValue(long ScreenVal) const CChartAxis [virtual]
ScrollBarEnabled() const CChartAxis [inline]
SetAutoHideScrollBar(bool bAutoHide)CChartAxis
SetAutomatic(bool bAutomatic)CChartAxis
SetAutomaticMode(EAxisAutoModes AutoMode)CChartAxis
SetAxisColor(COLORREF NewColor)CChartAxis
SetAxisToScrollStep(int iPreviousStep, int iCurrentStep, bool bScrollInverted)CChartAxis [protected, virtual]
SetDiscrete(bool bDiscrete)CChartAxis [virtual]
SetFont(int nPointSize, const TChartString &strFaceName)CChartAxis
SetInverted(bool bInverted)CChartAxis
SetMarginSize(bool bAuto, int iNewSize)CChartAxis
SetMinMax(double Minimum, double Maximum)CChartAxis
SetPanZoomEnabled(bool bEnabled)CChartAxis [inline]
SetTextColor(COLORREF NewColor)CChartAxis
SetVisible(bool bVisible)CChartAxis
SetZoomLimit(double dLimit)CChartAxis [inline]
SetZoomMinMax(double Minimum, double Maximum)CChartAxis [protected, virtual]
UndoZoom()CChartAxis [protected]
ValueToScreen(double Value) const CChartAxis
ValueToScreenDiscrete(double Value) const =0CChartAxis [protected, pure virtual]
ValueToScreenStandard(double Value) const CChartAxis [protected, virtual]
~CChartAxis()CChartAxis [virtual]

+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_axis.html b/ChartDemo/Doc/html/class_c_chart_axis.html new file mode 100644 index 0000000..b489650 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_axis.html @@ -0,0 +1,964 @@ + + +ChartDemo: CChartAxis Class Reference + + + + + +
+

CChartAxis Class Reference

Base class that takes care of the management of a chart axis. +More... +

+#include <ChartAxis.h> +

+

+Inheritance diagram for CChartAxis:
+
+ +

+ +CChartDateTimeAxis +CChartLogarithmicAxis +CChartStandardAxis + +
+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Types

enum  EAxisAutoModes { NotAutomatic, +FullAutomatic, +ScreenAutomatic + }
 The different modes of automatic modes for an axis. More...

Public Member Functions

CChartAxis ()
 Default constructor.
+virtual ~CChartAxis ()
 Default destructor.
+int GetPosition ()
 Retrieves the position (in %) of the axis.
void SetInverted (bool bInverted)
 Sets the axis in reverse.
+bool IsInverted () const
 Retrieves if the axis is inverted or not.
void SetAutomatic (bool bAutomatic)
 Sets the axis in automatic or manual mode.
bool IsAutomatic () const
 Returns true if an automatic mode has been set on this axis.
+void SetAutomaticMode (EAxisAutoModes AutoMode)
 Sets the automatic mode of the axis.
+EAxisAutoModes GetAutomaticMode () const
 Gets the automatic type of the axis.
+void SetVisible (bool bVisible)
 Sets the axis visible/invisible.
+bool IsVisible () const
 Retrieves the axis automatic mode.
void SetMinMax (double Minimum, double Maximum)
 Sets the axis min and max values.
+void GetMinMax (double &Minimum, double &Maximum) const
 Gets the min anx max values of the axis.
+void SetAxisColor (COLORREF NewColor)
 Sets the axis color.
+void SetTextColor (COLORREF NewColor)
 Sets the tick labels color.
+COLORREF GetTextColor () const
 Gets the tick labels color.
void SetFont (int nPointSize, const TChartString &strFaceName)
 Sets the tick labels font.
+CChartAxisLabelGetLabel () const
 Retrieves the chart axis label object.
+CChartGridGetGrid () const
 Retrieves the chart axis grid object.
void SetMarginSize (bool bAuto, int iNewSize)
 Sets the margin size.
+void SetPanZoomEnabled (bool bEnabled)
 Enable the pan and zoom for this axis.
void SetZoomLimit (double dLimit)
 Sets the zoom limit.
+void EnableScrollBar (bool bEnabled)
 Enables/disables the scroll bar.
+bool ScrollBarEnabled () const
 Retrieves if the scroll bar is enabled or not.
void SetAutoHideScrollBar (bool bAutoHide)
 Specifies if the scroll bar is in auto-hide mode.
+bool GetAutoHideScrollBar () const
 Retrieves if the scroll bar is in auto-hide mode.
virtual void SetDiscrete (bool bDiscrete)
 Sets the axis in discrete mode.
long ValueToScreen (double Value) const
 Converts a value on the axis to a screen position.
virtual double ScreenToValue (long ScreenVal) const
 Converts a screen position to a value on the axis.
+bool IsHorizontal () const
 Returns true if the axis is horizontal.
+BOOL IsPointInside (const CPoint &screenPoint) const
 Returns true if a screen point is in the region of the axis.

Protected Member Functions

virtual double GetFirstTickValue () const =0
 Returns the first tick value.
virtual bool GetNextTickValue (double dCurrentTick, double &dNextTick) const =0
 Retrieves the next tick value after a given tick.
virtual long GetTickPos (double Value) const =0
 Retrieves the screen position of a certain tick.
virtual long ValueToScreenDiscrete (double Value) const =0
 Converts a value on the axis to a screen position.
virtual long ValueToScreenStandard (double Value) const
 Converts a value on the axis to a screen position.
virtual TChartString GetTickLabel (double TickValue) const =0
 Retrieves the label for a specific tick.
+virtual void RefreshTickIncrement ()=0
 Forces a recalculation of the tick increment.
+virtual void RefreshFirstTick ()=0
 Forces a recalculation of the first tick value.
virtual void GetScrollbarSteps (int &iTotalSteps, int &iCurrentStep)
 Retrieves the step information related to the scrollbar.
virtual void SetAxisToScrollStep (int iPreviousStep, int iCurrentStep, bool bScrollInverted)
 Sets the axis to the specified scrollbar step.
virtual void PanAxis (long PanStart, long PanEnd)
 Pan the axis.
+virtual void SetZoomMinMax (double Minimum, double Maximum)
 Sets the min and max values of the axis due to a zoom operation.
+void UndoZoom ()
 Reverts the zoom and pan settings.
+long GetAxisLenght () const
 Retrieves the lenght (in pixels) of the axis.
+void GetSeriesMinMax (double &Minimum, double &Maximum)
 Retrieves the min and max values for all the series related to this axis.
+void GetSeriesScreenMinMax (double &Minimum, double &Maximum)
 Retrieves the screen min and max values for all the series related to this axis.

Protected Attributes

+CChartCtrlm_pParentCtrl
 The parent chart control.
+bool m_bIsHorizontal
 Indicates if this is an horizontal or vertical axis.
+bool m_bIsInverted
 Indicates if the axis is inverted.
EAxisAutoModes m_AutoMode
 Indicates if the axis is automatic.
+bool m_bIsVisible
 Indicates if the axis is visible or not.
bool m_bIsSecondary
 Specifies if the axis is secondary.
+double m_MaxValue
 The axis max value.
+double m_MinValue
 The axis min value.
+double m_UnzoomMin
 Min value of the axis before it has been zoomed.
+double m_UnzoomMax
 Max value of the axis before it has been zoomed.
+bool m_bAutoTicks
 Specify if the tick increment is manual or automatic.
+bool m_bDiscrete
 Specify if the axis has to be in discrete mode or not.
+int m_StartPos
 Start position of the axis (in pixels).
+int m_EndPos
 End position of the axis (in pixels).
+CRect m_AxisRect
 The rectangle in which the axis is contained.
+


Detailed Description

+Base class that takes care of the management of a chart axis. +

+This class cannot be instanciated but should be overriden in order to provide the required functionality (this is already done for standard axis, date/time axis and logarithmic axis).
+ The class provides already a lot of functionalities but delegate the ticks positioning and labeling to the child classes.
+ By default, the class manages a continues range of double values (which is the case for standard axis and date/time axis) but in some cases, this is not valid (for instance, a logarithmic scale). In that case, you should in addition override some specific functions (e.g. those handling the scrollbar). Take a look at the CChartLogarithmicAxis class for more details.


Member Enumeration Documentation

+ +
+
+ + + + +
enum CChartAxis::EAxisAutoModes
+
+
+ +

+The different modes of automatic modes for an axis. +

+

Enumerator:
+ + + + +
NotAutomatic  +The axis min and max values are set manually.
FullAutomatic  +The axis min and max values of the axis are the min and max values of all series associated with this axis. This corresponds to the "standard" automatic mode that was implemented before version 3.0.
ScreenAutomatic  +The axis min and max values of the axis are the visible min and max values of all series associated with this axis. The end result will then depends on how the other axes are configured.
+
+ +
+

+


Member Function Documentation

+ +
+
+ + + + + + + + +
virtual double CChartAxis::GetFirstTickValue (  )  const [protected, pure virtual]
+
+
+ +

+Returns the first tick value. +

+This pure virtual function must be implemented for specific axes type. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
virtual bool CChartAxis::GetNextTickValue (double  dCurrentTick,
double &  dNextTick 
) const [protected, pure virtual]
+
+
+ +

+Retrieves the next tick value after a given tick. +

+This pure virtual function must be implemented for specific axes type.

Parameters:
+ + + +
dCurrentTick The value of the current tick
dNextTick The value of the next tick will be stored in this parameter
+
+
Returns:
true if there is a next or false when the current tick is the last one.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartAxis::GetScrollbarSteps (int &  iTotalSteps,
int &  iCurrentStep 
) [protected, virtual]
+
+
+ +

+Retrieves the step information related to the scrollbar. +

+This function can be implemented for specific axis types which should provide a behavior different than the standard behavior (for instance log axis).

Parameters:
+ + + +
iTotalSteps Stores the total number of steps for the scrollbar
iCurrentStep Stores the current step index for the scrollbar
+
+ +
+

+ +

+
+ + + + + + + + + +
virtual TChartString CChartAxis::GetTickLabel (double  TickValue  )  const [protected, pure virtual]
+
+
+ +

+Retrieves the label for a specific tick. +

+This pure virtual function must be implemented for specific axes type.

Parameters:
+ + +
TickValue The tick value for which we need to get the label.
+
+
Returns:
A TChartString containing the label for the tick.
+ +
+

+ +

+
+ + + + + + + + + +
virtual long CChartAxis::GetTickPos (double  Value  )  const [protected, pure virtual]
+
+
+ +

+Retrieves the screen position of a certain tick. +

+This pure virtual function must be implemented for specific axes type.

Parameters:
+ + +
Value The value of the tick for which we want to retrieve the position
+
+
Returns:
the screen position of the tick
+ +
+

+ +

+
+ + + + + + + + +
bool CChartAxis::IsAutomatic (  )  const [inline]
+
+
+ +

+Returns true if an automatic mode has been set on this axis. +

+

Deprecated:
You should use the GetAutomaticType instead.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartAxis::PanAxis (long  PanStart,
long  PanEnd 
) [protected, virtual]
+
+
+ +

+Pan the axis. +

+This function can be overriden in case the axis doesn't display a continuous range of values (e.g. log axis).

Parameters:
+ + + +
PanStart The position of the start of the pan
PanEnd The position of the end of the pan
+
+ +
+

+ +

+
+ + + + + + + + + +
double CChartAxis::ScreenToValue (long  ScreenVal  )  const [virtual]
+
+
+ +

+Converts a screen position to a value on the axis. +

+The function is implemented for an axis with a standard behavior (the axis shows a continuous range of doubles). It is the case for standard axis and date/time axis (date are converted to doubles internally). Axis that needs a different behavior should override this function (e.g. a logarithmic axis). The function does not take care of the discrete mode.

Parameters:
+ + +
ScreenVal The screen value to convert
+
+
Returns:
the double value
+ +
+

+ +

+
+ + + + + + + + + +
void CChartAxis::SetAutoHideScrollBar (bool  bAutoHide  ) 
+
+
+ +

+Specifies if the scroll bar is in auto-hide mode. +

+In auto-hide mode, the scroll bar will be hidden until you hover the mouse over it. +

+

+ +

+
+ + + + + + + + + +
void CChartAxis::SetAutomatic (bool  bAutomatic  ) 
+
+
+ +

+Sets the axis in automatic or manual mode. +

+In automatic mode, the axis min and max will be updated depending on the series related to this axis.

Parameters:
+ + +
bAutomatic true if the axis should be automatic.
+
+
Deprecated:
You should use the SetAutomaticType instead.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void CChartAxis::SetAxisToScrollStep (int  iPreviousStep,
int  iCurrentStep,
bool  bScrollInverted 
) [protected, virtual]
+
+
+ +

+Sets the axis to the specified scrollbar step. +

+This function can be implemented for specific axis types which should provide a behavior different than the standard behavior (for instance log axis).

Parameters:
+ + + + +
iPreviousStep The previous scroll step.
iCurrentStep The current scroll step to which the axis should be moved.
bScrollInverted Specifies if the scroll is inverted or not.
+
+ +
+

+ +

+
+ + + + + + + + + +
void CChartAxis::SetDiscrete (bool  bDiscrete  )  [virtual]
+
+
+ +

+Sets the axis in discrete mode. +

+

Parameters:
+ + +
bDiscrete true if the axis has to be discrete, false otherwise. In discrete mode, the axis doesn't have a continuous range of values but only steps which are defined by the tick interval. In this mode, you won't be able to plot points at a different location that in the middle of two ticks. For instance, if you have a tick interval of 1.0, trying to plot a value of 0.9 will display the point at the same position as if the value was 0.3: it will be displayed in the middle of tick 0.0 and tick 1.0.
+It is mainly used to display the tick label in the middle of two ticks. This is for instance nice with date/time axis.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartAxis::SetFont (int  nPointSize,
const TChartString &  strFaceName 
)
+
+
+ +

+Sets the tick labels font. +

+

Parameters:
+ + + +
nPointSize The font point size
strFaceName The font face name
+
+ +
+

+ +

+
+ + + + + + + + + +
void CChartAxis::SetInverted (bool  bInverted  ) 
+
+
+ +

+Sets the axis in reverse. +

+For an inverted axis, the values on the axis are in decreasing order.

Parameters:
+ + +
bInverted true if the axis has to be inverted.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartAxis::SetMarginSize (bool  bAuto,
int  iNewSize 
)
+
+
+ +

+Sets the margin size. +

+

Parameters:
+ + + +
bAuto Specifies if the margin size is automatic or not. In automatic mode, the iNewSize parameter is ignored and the margin size is calculated automatically.
iNewSize The new size of the margin, in manual mode.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartAxis::SetMinMax (double  Minimum,
double  Maximum 
)
+
+
+ +

+Sets the axis min and max values. +

+This doesn't take into account the real type of the axis, so double values should be provided.

Parameters:
+ + + +
Minimum The min value of the axis
Maximum The max value of the axis.
+
+ +
+

+ +

+
+ + + + + + + + + +
void CChartAxis::SetZoomLimit (double  dLimit  )  [inline]
+
+
+ +

+Sets the zoom limit. +

+The zoom limit is the minimum lenght (in values) of the axis. +

+

+ +

+
+ + + + + + + + + +
long CChartAxis::ValueToScreen (double  Value  )  const
+
+
+ +

+Converts a value on the axis to a screen position. +

+The functions takes care of the discrete mode (internally, it calls ValueToScreenStandard or ValueToScreenDiscrete depending on the discrete mode).

Parameters:
+ + +
Value The value to convert
+
+
Returns:
the screen position of the value
+ +
+

+ +

+
+ + + + + + + + + +
virtual long CChartAxis::ValueToScreenDiscrete (double  Value  )  const [protected, pure virtual]
+
+
+ +

+Converts a value on the axis to a screen position. +

+This function is called internally only when the axis is in discrete mode. This pure virtual function must be implemented for specific axes type.

Parameters:
+ + +
Value The value to convert
+
+
Returns:
the screen position of the value
+ +
+

+ +

+
+ + + + + + + + + +
long CChartAxis::ValueToScreenStandard (double  Value  )  const [protected, virtual]
+
+
+ +

+Converts a value on the axis to a screen position. +

+This function is called internally only when the axis is in standard mode. This virtual function can be overriden when the axis doesn't display a continuous range of values (e.g. log axis).

Parameters:
+ + +
Value The value to convert
+
+
Returns:
the screen position of the value
+ +
+

+


Member Data Documentation

+ +
+
+ + + + +
EAxisAutoModes CChartAxis::m_AutoMode [protected]
+
+
+ +

+Indicates if the axis is automatic. +

+Indicates the automatic mode of the axis +

+

+ +

+
+ + + + +
bool CChartAxis::m_bIsSecondary [protected]
+
+
+ +

+Specifies if the axis is secondary. +

+The secondary axis is either on the top (for horizontal axis) or on the right (for vertical axis) of the chart. +

+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartAxis.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartAxis.cpp
+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_axis.png b/ChartDemo/Doc/html/class_c_chart_axis.png new file mode 100644 index 0000000000000000000000000000000000000000..02904cef6bc186d3219ef6c242f2d6f0eff75a97 GIT binary patch literal 913 zcmV;C18)3@P)RCt{2m~D=v zAP|Nzo6K*kZcxqzCOyfX$7GYf{}GldJ_NyTOwdNdI};m9e60uQvZGSK!Xr3vK{8(n|P!T)L8V8gz1X+m%D01OHSdc5mz&QG}^#}~1gKS#kZA0gjN>|(r(UDOQ|&ZYHm=ZHsQh-U}V%7!~p zFT|6JFl0*cqT3{P5nkSoHt;fOJ(fWzchaNuj3EG-shR*eAnf7|k`MQBf;Ap`Gkps9 zj%L-l$>TYqV|*J#GB=3rBD@Vd$;!lxgZ4tqrM1RGlKBFeVQG_{K;1$x9kg*jjVYcO zkoA+TfwV;U0EC#a%i{%hgp=t=41BuTwAOgiwBt-Wz?*`62!lPASv^O!-~|zTu!%%= z8>_cmEJOX&`*ibZW$?^*7wzWc8G-5#hl{0uyah;S(AlunhPE!;X zyu@znx##V;%as!)=F*iqm8Ny(ua@)yn9)^#l;OSc2wtDJx+-3wI$p6lUZGFND^p#( nf;VmjDt!@HqS6 + +ChartDemo: Member List + + + + + +
+

CChartAxisLabel Member List

This is the complete list of members for CChartAxisLabel, including all inherited members.

+ + + + + + + + +
GetColor() const CChartAxisLabel [inline]
GetText() const CChartAxisLabel [inline]
IsVisible() const CChartAxisLabel [inline]
SetColor(COLORREF NewColor)CChartAxisLabel
SetFont(int nPointSize, const TChartString &strFaceName)CChartAxisLabel
SetFont(const CChartFont &newFont)CChartAxisLabel
SetText(const TChartString &NewText)CChartAxisLabel
SetVisible(bool bVisible)CChartAxisLabel

+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_axis_label.html b/ChartDemo/Doc/html/class_c_chart_axis_label.html new file mode 100644 index 0000000..f6941bf --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_axis_label.html @@ -0,0 +1,142 @@ + + +ChartDemo: CChartAxisLabel Class Reference + + + + + +
+

CChartAxisLabel Class Reference

Draws the label of an axis. +More... +

+#include <ChartAxisLabel.h> +

+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

+void SetText (const TChartString &NewText)
 Sets the text of the axis label.
+TChartString GetText () const
 Retrieves the text of the axis label.
void SetFont (int nPointSize, const TChartString &strFaceName)
 Sets the font of the text.
void SetFont (const CChartFont &newFont)
 Sets the font of the text.
+void SetVisible (bool bVisible)
 Shows/hides the title.
+bool IsVisible () const
 Returns true if the title is visible.
+COLORREF GetColor () const
 Retrieves the text color.
+void SetColor (COLORREF NewColor)
 Sets the text color.
+


Detailed Description

+Draws the label of an axis. +

+The label axis is displayed under or next to the tick values. The label is retrieved by calling CChartAxis::GetAxisLabel.


Member Function Documentation

+ +
+
+ + + + + + + + + +
void CChartAxisLabel::SetFont (const CChartFont newFont  ) 
+
+
+ +

+Sets the font of the text. +

+This function allows to set extended font style by passing a CChartFont object.

Parameters:
+ + +
newFont The new font.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartAxisLabel::SetFont (int  nPointSize,
const TChartString &  strFaceName 
)
+
+
+ +

+Sets the font of the text. +

+

Parameters:
+ + + +
nPointSize The font point size.
strFaceName The font face name ("Times New Roman", "Arial", ...)
+
+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartAxisLabel.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartAxisLabel.cpp
+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_balloon_label-members.html b/ChartDemo/Doc/html/class_c_chart_balloon_label-members.html new file mode 100644 index 0000000..a82cf33 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_balloon_label-members.html @@ -0,0 +1,57 @@ + + +ChartDemo: Member List + + + + + +
+

CChartBalloonLabel< PointType > Member List

This is the complete list of members for CChartBalloonLabel< PointType >, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
CChartBalloonLabel(CChartCtrl *pParentCtrl, CChartSerieBase< PointType > *pParentSeries)CChartBalloonLabel< PointType > [inline]
CChartLabel(CChartCtrl *pParentCtrl, CChartSerieBase< PointType > *pParentSeries)CChartLabel< PointType > [inline, protected]
Draw(CDC *pDC, unsigned uPointIndex)CChartBalloonLabel< PointType > [inline, protected, virtual]
GetBackgroundColor() const CChartBalloonLabel< PointType > [inline]
GetBorderColor() const CChartBalloonLabel< PointType > [inline]
GetLineColor() const CChartBalloonLabel< PointType > [inline]
GetRoundedRect() const CChartBalloonLabel< PointType > [inline]
m_bIsVisibleCChartLabel< PointType > [protected]
m_iFontSizeCChartLabel< PointType > [protected]
m_pLabelProviderCChartLabel< PointType > [protected]
m_pParentCtrlCChartLabel< PointType > [protected]
m_pParentSeriesCChartLabel< PointType > [protected]
m_strFontNameCChartLabel< PointType > [protected]
m_strLabelTextCChartLabel< PointType > [protected]
SetBackgroundColor(COLORREF colBackground)CChartBalloonLabel< PointType > [inline]
SetBorderColor(COLORREF colBorder)CChartBalloonLabel< PointType > [inline]
SetFont(int nPointSize, const TChartString &strFaceName)CChartBalloonLabel< PointType > [inline]
SetFont(const CChartFont &newFont)CChartBalloonLabel< PointType > [inline]
SetLabelProvider(CChartLabelProvider< PointType > *pProvider)CChartLabel< PointType > [inline]
SetLabelText(const TChartString &strText)CChartLabel< PointType > [inline]
SetLineColor(COLORREF colArrow)CChartBalloonLabel< PointType > [inline]
SetRoundedRect(bool bRounded)CChartBalloonLabel< PointType > [inline]
SetVisisble(bool bVisible)CChartLabel< PointType > [inline]
~CChartBalloonLabel()CChartBalloonLabel< PointType > [inline]
~CChartLabel()CChartLabel< PointType > [inline, protected, virtual]

+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_balloon_label.html b/ChartDemo/Doc/html/class_c_chart_balloon_label.html new file mode 100644 index 0000000..037ee8b --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_balloon_label.html @@ -0,0 +1,181 @@ + + +ChartDemo: CChartBalloonLabel< PointType > Class Template Reference + + + + + +
+

CChartBalloonLabel< PointType > Class Template Reference

Specialization of the CChartLabel to display a balloon label. +More... +

+#include <ChartBalloonLabel.h> +

+

+Inheritance diagram for CChartBalloonLabel< PointType >:
+
+ +

+ +CChartLabel< PointType > + +
+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

+void SetBackgroundColor (COLORREF colBackground)
 Sets the background color of the text area.
+COLORREF GetBackgroundColor () const
 Retrieves the background color of the text area.
+void SetLineColor (COLORREF colArrow)
 Sets the color of the line connecting the point to the text area.
+COLORREF GetLineColor () const
 Retrieves the color of the line connecting the point to the text area.
+void SetBorderColor (COLORREF colBorder)
 Sets the color of border's text area.
+COLORREF GetBorderColor () const
 Retrieves the color of border's text area.
+void SetRoundedRect (bool bRounded)
 Specifies if the text area is rounded or not.
+bool GetRoundedRect () const
 Returns true if the text area is rounded.
void SetFont (int nPointSize, const TChartString &strFaceName)
 Sets the font of the text.
void SetFont (const CChartFont &newFont)
 Sets the font of the text.
CChartBalloonLabel (CChartCtrl *pParentCtrl, CChartSerieBase< PointType > *pParentSeries)
 Constructor.
~CChartBalloonLabel ()
 Destructor.

Protected Member Functions

+void Draw (CDC *pDC, unsigned uPointIndex)
 Draw the label.
+


Detailed Description

+

template<class PointType>
+ class CChartBalloonLabel< PointType >

+ +Specialization of the CChartLabel to display a balloon label. +

+A balloon label is a label with a rounded rectangle area in which the text is displayed and which is connected with a line to the point to which it is attached.


Member Function Documentation

+ +
+
+
+template<class PointType >
+ + + + + + + + + +
void CChartBalloonLabel< PointType >::SetFont (const CChartFont newFont  )  [inline]
+
+
+ +

+Sets the font of the text. +

+This function allows to set extended font style by passing a CChartFont object.

Parameters:
+ + +
newFont The new font.
+
+ +
+

+ +

+
+
+template<class PointType >
+ + + + + + + + + + + + + + + + + + +
void CChartBalloonLabel< PointType >::SetFont (int  nPointSize,
const TChartString &  strFaceName 
) [inline]
+
+
+ +

+Sets the font of the text. +

+

Parameters:
+ + + +
nPointSize The font point size.
strFaceName The font face name ("Times New Roman", "Arial", ...)
+
+ +

Reimplemented from CChartLabel< PointType >.

+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartBalloonLabel.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartBalloonLabel.inl
+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_balloon_label.png b/ChartDemo/Doc/html/class_c_chart_balloon_label.png new file mode 100644 index 0000000000000000000000000000000000000000..b1c050097eccfcd88bc57f2123bf1886281ac3ef GIT binary patch literal 613 zcmV-r0-F7aP)NO zAPk0K)3wA6-~^raLRsbhN2ngi#z0&rO=yyVjU@%?(+^@M?t94kbYE%2nw%HoAf^;C zq+o$)=JpeLqqzYQL)u$4Cvs+3i(lrXb&DiirzdC$ZjrQ6K563^E7VBIVK>GQG51F{ z3B8JgltmU5;TW4a68Jaeh^sp?M{McqupTR)&rJ%bCpGwfl#>chGENQJ5sR&?djB$tE1+ zK+&J2bva%w?uK%x9YB->9(yklwp1^9d0WX5mv+cQ@oGDSOB|}o5mY_0Um|R2P&^A# zLgt8@)7-LK`hpI}4 z@&Wbc?e436MUUaY7>-`!<2ju*InT}+^uOu{$bov;(qGY;00000NkvXXu0mjfLf0aI literal 0 HcmV?d00001 diff --git a/ChartDemo/Doc/html/class_c_chart_bar_serie-members.html b/ChartDemo/Doc/html/class_c_chart_bar_serie-members.html new file mode 100644 index 0000000..b644e1e --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_bar_serie-members.html @@ -0,0 +1,119 @@ + + +ChartDemo: Member List + + + + + +
+

CChartBarSerie Member List

This is the complete list of members for CChartBarSerie, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AddPoint(double X, double Y)CChartXYSerie
CChartSerieBase< SChartXYPoint >::AddPoint(const SChartXYPoint &newPoint)CChartSerieBase< SChartXYPoint >
AddPoints(double *pX, double *pY, unsigned Count)CChartXYSerie
CChartSerieBase< SChartXYPoint >::AddPoints(SChartXYPoint *pPoints, unsigned Count)CChartSerieBase< SChartXYPoint >
AttachCustomLabel(unsigned uPointIndex, CChartLabel< SChartXYPoint > *pLabel)CChartSerieBase< SChartXYPoint >
CChartBarSerie(CChartCtrl *pParent)CChartBarSerie
CChartSerie(CChartCtrl *pParent)CChartSerie
CChartSerieBase(CChartCtrl *pParent)CChartSerieBase< SChartXYPoint >
CChartXYSerie(CChartCtrl *pParent)CChartXYSerie
ClearSerie()CChartSerieBase< SChartXYPoint >
CreateBalloonLabel(unsigned uPointIndex, const TChartString &strLabelText)CChartSerieBase< SChartXYPoint >
CreateBalloonLabel(unsigned uPointIndex, CChartLabelProvider< SChartXYPoint > *pLabelProvider)CChartSerieBase< SChartXYPoint >
EnableMouseNotifications(bool bClickEnabled, bool bMoveEnabled)CChartSerie
EnableShadow(bool bEnable)CChartSerie
GetBarWidth() const CChartBarSerie [inline]
GetBezierControlPoints(unsigned uFirst, unsigned uLast, SChartXYPoint *&pKnots, SChartXYPoint *&pFirstControlPoints, SChartXYPoint *&pSecondControlPoints) const CChartXYSerie [protected]
GetBorderColor() const CChartBarSerie [inline]
GetBorderWidth() const CChartBarSerie [inline]
GetColor() const CChartSerie [inline]
GetGroupId() const CChartBarSerie [inline]
GetHorizontal() const CChartBarSerie [inline]
GetInterSpace()CChartBarSerie [inline, static]
GetName() const CChartSerie [inline]
GetPoint(unsigned index) constCChartSerieBase< SChartXYPoint >
GetPointsCount() constCChartSerieBase< SChartXYPoint > [inline, virtual]
GetPointScreenCoord(unsigned uPointIndex)CChartSerieBase< SChartXYPoint > [virtual]
GetSerieId() const CChartSerie [inline]
GetSerieXMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetSerieXScreenMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetSerieYMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetSerieYScreenMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetShadowColor() const CChartSerie [inline]
GetUserData(unsigned uPointIndex)CChartXYSerie
GetVisiblePoints(unsigned &uFirst, unsigned &uLast) constCChartSerieBase< SChartXYPoint > [protected, virtual]
GetXPointValue(unsigned PointIndex) const CChartXYSerie
GetYPointValue(unsigned PointIndex) const CChartXYSerie
IsPointOnSerie(const CPoint &screenPoint, unsigned &uIndex) const CChartBarSerie [virtual]
IsStacked()CChartBarSerie
IsVisible() const CChartSerie [inline]
m_bIsVisibleCChartSerie [protected]
m_bShadowCChartSerie [protected]
m_iShadowDepthCChartSerie [protected]
m_pHorizontalAxisCChartSerie [protected]
m_PlottingRectCChartSerie [protected]
m_pParentCtrlCChartSerie [protected]
m_pVerticalAxisCChartSerie [protected]
m_SerieColorCChartSerie [protected]
m_ShadowColorCChartSerie [protected]
m_strSerieNameCChartSerie [protected]
m_uLastDrawnPointCChartSerieBase< SChartXYPoint > [protected]
m_vPointsCChartSerieBase< SChartXYPoint > [protected]
NotifyMouseClickEnabled()CChartSerie [inline, protected]
NotifyMouseMoveEnabled()CChartSerie [inline, protected]
OnMouseEvent(CChartMouseListener::MouseEvent mouseEvent, const CPoint &screenPoint)CChartSerieBase< SChartXYPoint > [protected, virtual]
RefreshAutoAxes()CChartSerie [protected]
RegisterMouseListener(CChartSeriesMouseListener< SChartXYPoint > *pListener)CChartSerieBase< SChartXYPoint >
RemovePointsFromBegin(unsigned Count)CChartSerieBase< SChartXYPoint >
RemovePointsFromEnd(unsigned Count)CChartSerieBase< SChartXYPoint >
SetBarWidth(int Width)CChartBarSerie
SetBaseLine(bool bAutomatic, double dBaseLine)CChartBarSerie [inline]
SetBorderColor(COLORREF BorderColor)CChartBarSerie
SetBorderWidth(int Width)CChartBarSerie
SetColor(COLORREF NewColor)CChartSerie
SetGradient(COLORREF GradientColor, EGradientType GradientType)CChartBarSerie
SetGroupId(unsigned GroupId)CChartBarSerie
SetHorizontal(bool bHorizontal)CChartBarSerie
SetInterSpace(int Space)CChartBarSerie [inline, static]
SetName(const TChartString &NewName)CChartSerie
SetPoints(double *pX, double *pY, unsigned Count)CChartXYSerie
CChartSerieBase< SChartXYPoint >::SetPoints(SChartXYPoint *pPoints, unsigned Count)CChartSerieBase< SChartXYPoint >
SetSeriesOrdering(PointsOrdering newOrdering)CChartSerieBase< SChartXYPoint > [virtual]
SetShadowColor(COLORREF NewColor)CChartSerie
SetShadowDepth(int Depth)CChartSerie
SetStacked(bool bStacked)CChartBarSerie
SetUserData(unsigned uPointIndex, void *pData)CChartXYSerie
SetVisible(bool bVisible)CChartSerie
SetXPointValue(unsigned PointIndex, double NewVal)CChartXYSerie
SetYPointValue(unsigned PointIndex, double NewVal)CChartXYSerie
ShowGradient(bool bShow)CChartBarSerie
UnregisterMouseListener()CChartSerieBase< SChartXYPoint >
ValueToScreen(double XValue, double YValue, CPoint &ScreenPoint) const CChartSerie
XScreenToValue(long XScreenCoord) const CChartSerie
YScreenToValue(long YScreenCoord) const CChartSerie
~CChartBarSerie()CChartBarSerie
~CChartSerie()CChartSerie [virtual]
~CChartSerieBase()CChartSerieBase< SChartXYPoint > [virtual]
~CChartXYSerie()CChartXYSerie [virtual]

+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_bar_serie.html b/ChartDemo/Doc/html/class_c_chart_bar_serie.html new file mode 100644 index 0000000..08f2715 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_bar_serie.html @@ -0,0 +1,293 @@ + + +ChartDemo: CChartBarSerie Class Reference + + + + + +
+

CChartBarSerie Class Reference

Specialization of a CChartSerie to display a bars series. +More... +

+#include <ChartBarSerie.h> +

+

+Inheritance diagram for CChartBarSerie:
+
+ +

+ +CChartXYSerie +CChartSerieBase< SChartXYPoint > +CChartSerie + +
+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

CChartBarSerie (CChartCtrl *pParent)
 Constructor.
~CChartBarSerie ()
 Destructor.
+void SetHorizontal (bool bHorizontal)
 Specifies if the bars are vertical or horizontal.
+bool GetHorizontal () const
 Returns true if bars are horizontal, false otherwise.
+void SetBorderColor (COLORREF BorderColor)
 Sets the bars border color.
+COLORREF GetBorderColor () const
 Returns the bars border color.
+void SetBorderWidth (int Width)
 Sets the bars border width.
+int GetBorderWidth () const
 Returns the bars border width.
+void SetBarWidth (int Width)
 Sets the bars width (in pixels).
+int GetBarWidth () const
 Returns the bars width (in pixels).
void SetGroupId (unsigned GroupId)
 Set the group Id of the series.
+unsigned GetGroupId () const
 Returns the group Id of the series.
void SetStacked (bool bStacked)
 Specifies if the series is stacked with other bar series.
+bool IsStacked ()
 Returns true if the series is stacked.
+void ShowGradient (bool bShow)
 Specifies if a gradient is applied to the bars.
void SetGradient (COLORREF GradientColor, EGradientType GradientType)
 Sets the gradient style.
void SetBaseLine (bool bAutomatic, double dBaseLine)
 Specifies a base line for the bars.
bool IsPointOnSerie (const CPoint &screenPoint, unsigned &uIndex) const
 Check whether a screen point is on the series.

Static Public Member Functions

+static void SetInterSpace (int Space)
 Static function used to specify the space (in pixels) between series of the same group.
+static int GetInterSpace ()
 Static function returning the space between series of the same group.
+


Detailed Description

+Specialization of a CChartSerie to display a bars series. +

+This class is a specialized series class used to display vertical (default) or horizontal bars. Each bar in the series is centered around its X value (for vertical bars) or Y value (for horizontal bars). Bars can be grouped together, so that they do not overlap but are stacked next to each other (or on top of each other). This is done by specifying a group Id: bar series with the same group Id will be grouped together (stacked). Series with different group Id will be independant (they will be drawn as if they were the only one, meaning that the different series will probably overlap).


Member Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
bool CChartBarSerie::IsPointOnSerie (const CPoint &  screenPoint,
unsigned &  uIndex 
) const [virtual]
+
+
+ +

+Check whether a screen point is on the series. +

+This function returns true if the screen point is on one of the bars of the series. In that case, the index of the point is stored in the uIndex parameter.

Parameters:
+ + + +
screenPoint The screen point to test
uIndex If the point is close to a specific point of the series, its index is stored here.
+
+
Returns:
true if the point is on the series
+ +

Implements CChartSerie.

+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartBarSerie::SetBaseLine (bool  bAutomatic,
double  dBaseLine 
) [inline]
+
+
+ +

+Specifies a base line for the bars. +

+If a baseline is specified, the bars will be drawn between that value and the point value, instead of being drawn between the axis ans the point value.

Parameters:
+ + + +
bAutomatic If true, the bars are drawn between the axis and the point value.
dBaseLine The value of the baseline. This parameter is ignored if bAutomatic is true.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartBarSerie::SetGradient (COLORREF  GradientColor,
EGradientType  GradientType 
)
+
+
+ +

+Sets the gradient style. +

+

Parameters:
+ + + +
GradientColor The second color used for the gradient (the first one being the original series color).
GradientType The type of gradient used between the two colors (vertical, horizontal, ...)
+
+ +
+

+ +

+
+ + + + + + + + + +
void CChartBarSerie::SetGroupId (unsigned  GroupId  ) 
+
+
+ +

+Set the group Id of the series. +

+The group Id allows to stack series next to each other (or on top of each other). +

+

+ +

+
+ + + + + + + + + +
void CChartBarSerie::SetStacked (bool  bStacked  ) 
+
+
+ +

+Specifies if the series is stacked with other bar series. +

+All bar series with the same group Id and with the stacked flag to true will be drawn on top of each other (for vertical bars). +

+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartBarSerie.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartBarSerie.cpp
+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_bar_serie.png b/ChartDemo/Doc/html/class_c_chart_bar_serie.png new file mode 100644 index 0000000000000000000000000000000000000000..40f17a258272dc13523e453b73aaeacd1b0fe750 GIT binary patch literal 831 zcmeAS@N?(olHy`uVBq!ia0vp^w}JQo3p0?c-@~m9q$C1-LR|m<{|{vT|9@cq{DcWW z78oBmaG?6o|0h5$V@Z%-FoVOh8)*y-OjkW!978JRyq)Dc>9GP&>)B=3r{yX5T`(

UCCn0O5zkEOQo9*9Db*X~u$2kjoTmrLrU#I5D z^gT97pEXr_PFz{>w}(e2u2kThvnNSuwYOh)N2qL*x8KIRC4Xn0UiwO4j_A$j>c@{J z7fPAg*>hV?dSNl=@D7*0@UJ)jo!E0&cGJwWwaaH~ifL5c7ks{IUF5y5!K@Y!^!luS zcHhtb_Vv+@^9Sz!i;M@yIHKX?B!;<;gQ%GdqiKnN@0~ z3d(%mab?Goqwfp&Lz`x`Pn&eP|Kjc&^?I?&pPM!pP7!{xr>S~{(2tuxZ~lmyGr7Ge zW?P`S=B=BBYqHPoxxb@yszcG2j(x?v((88Ixw_}G>(TiZkN+N9yP74{xHutzb86G% z9eb`7c9+X)9lUkZbmGq5>~rg!RR#7xF*BO|yKk-T*^{lQvt287?Ug^j(t%-G+B+%ewikR`VFb@>h19eFzwc+O3}@^NB}Kx}0~ zpRE1j`_0jlxtFB!e2U$n-aBWO z7d2jsPB|7h(ee^7RCjR5KGZF^AZRCs5z=nyw`|TT&%I~#K(Ciub6(INzeGuqOR3wU zxV}G*J90L2*@7N6^Qnp6D^G7LJh*$QlgEQ6r+rc;JSpM0Hp{zlp5GSn>2of(>9WS z#Fm# + +ChartDemo: Member List + + + + +

+
+

CChartCandlestickSerie Member List

This is the complete list of members for CChartCandlestickSerie, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AddPoint(double XVal, double Low, double High, double Open, double Close)CChartCandlestickSerie
CChartSerieBase< SChartCandlestickPoint >::AddPoint(const SChartCandlestickPoint &newPoint)CChartSerieBase< SChartCandlestickPoint >
AddPoints(SChartCandlestickPoint *pPoints, unsigned Count)CChartSerieBase< SChartCandlestickPoint >
AttachCustomLabel(unsigned uPointIndex, CChartLabel< SChartCandlestickPoint > *pLabel)CChartSerieBase< SChartCandlestickPoint >
CChartCandlestickSerie(CChartCtrl *pParent)CChartCandlestickSerie
CChartSerie(CChartCtrl *pParent)CChartSerie
CChartSerieBase(CChartCtrl *pParent)CChartSerieBase< SChartCandlestickPoint >
ClearSerie()CChartSerieBase< SChartCandlestickPoint >
CreateBalloonLabel(unsigned uPointIndex, const TChartString &strLabelText)CChartSerieBase< SChartCandlestickPoint >
CreateBalloonLabel(unsigned uPointIndex, CChartLabelProvider< SChartCandlestickPoint > *pLabelProvider)CChartSerieBase< SChartCandlestickPoint >
Draw(CDC *pDC)CChartCandlestickSerie [protected, virtual]
DrawAll(CDC *pDC)CChartCandlestickSerie [protected, virtual]
DrawLegend(CDC *pDC, const CRect &rectBitmap) const CChartCandlestickSerie [protected, virtual]
EnableMouseNotifications(bool bClickEnabled, bool bMoveEnabled)CChartSerie
EnableShadow(bool bEnable)CChartSerie
GetColor() const CChartSerie [inline]
GetName() const CChartSerie [inline]
GetPoint(unsigned index) constCChartSerieBase< SChartCandlestickPoint >
GetPointsCount() constCChartSerieBase< SChartCandlestickPoint > [inline, virtual]
GetPointScreenCoord(unsigned uPointIndex)CChartSerieBase< SChartCandlestickPoint > [virtual]
GetSerieId() const CChartSerie [inline]
GetSerieXMinMax(double &Min, double &Max) constCChartSerieBase< SChartCandlestickPoint > [virtual]
GetSerieXScreenMinMax(double &Min, double &Max) constCChartSerieBase< SChartCandlestickPoint > [virtual]
GetSerieYMinMax(double &Min, double &Max) constCChartSerieBase< SChartCandlestickPoint > [virtual]
GetSerieYScreenMinMax(double &Min, double &Max) constCChartSerieBase< SChartCandlestickPoint > [virtual]
GetShadowColor() const CChartSerie [inline]
GetVisiblePoints(unsigned &uFirst, unsigned &uLast) constCChartSerieBase< SChartCandlestickPoint > [protected, virtual]
GetWidth()CChartCandlestickSerie [inline]
IsPointOnSerie(const CPoint &screenPoint, unsigned &uIndex) const CChartCandlestickSerie [virtual]
IsVisible() const CChartSerie [inline]
m_bIsVisibleCChartSerie [protected]
m_bShadowCChartSerie [protected]
m_iShadowDepthCChartSerie [protected]
m_pHorizontalAxisCChartSerie [protected]
m_PlottingRectCChartSerie [protected]
m_pParentCtrlCChartSerie [protected]
m_pVerticalAxisCChartSerie [protected]
m_SerieColorCChartSerie [protected]
m_ShadowColorCChartSerie [protected]
m_strSerieNameCChartSerie [protected]
m_uLastDrawnPointCChartSerieBase< SChartCandlestickPoint > [protected]
m_vPointsCChartSerieBase< SChartCandlestickPoint > [protected]
NotifyMouseClickEnabled()CChartSerie [inline, protected]
NotifyMouseMoveEnabled()CChartSerie [inline, protected]
OnMouseEvent(CChartMouseListener::MouseEvent mouseEvent, const CPoint &screenPoint)CChartSerieBase< SChartCandlestickPoint > [protected, virtual]
RefreshAutoAxes()CChartSerie [protected]
RegisterMouseListener(CChartSeriesMouseListener< SChartCandlestickPoint > *pListener)CChartSerieBase< SChartCandlestickPoint >
RemovePointsFromBegin(unsigned Count)CChartSerieBase< SChartCandlestickPoint >
RemovePointsFromEnd(unsigned Count)CChartSerieBase< SChartCandlestickPoint >
SetColor(COLORREF NewColor)CChartSerie
SetName(const TChartString &NewName)CChartSerie
SetPoints(SChartCandlestickPoint *pPoints, unsigned Count)CChartSerieBase< SChartCandlestickPoint >
SetSeriesOrdering(PointsOrdering newOrdering)CChartSerieBase< SChartCandlestickPoint > [virtual]
SetShadowColor(COLORREF NewColor)CChartSerie
SetShadowDepth(int Depth)CChartSerie
SetVisible(bool bVisible)CChartSerie
SetWidth(int Width)CChartCandlestickSerie
UnregisterMouseListener()CChartSerieBase< SChartCandlestickPoint >
ValueToScreen(double XValue, double YValue, CPoint &ScreenPoint) const CChartSerie
XScreenToValue(long XScreenCoord) const CChartSerie
YScreenToValue(long YScreenCoord) const CChartSerie
~CChartCandlestickSerie()CChartCandlestickSerie
~CChartSerie()CChartSerie [virtual]
~CChartSerieBase()CChartSerieBase< SChartCandlestickPoint > [virtual]

+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_candlestick_serie.html b/ChartDemo/Doc/html/class_c_chart_candlestick_serie.html new file mode 100644 index 0000000..6e689e3 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_candlestick_serie.html @@ -0,0 +1,285 @@ + + +ChartDemo: CChartCandlestickSerie Class Reference + + + + + +
+

CChartCandlestickSerie Class Reference

Specialization of a CChartSerieBase to display a candlestick series. +More... +

+#include <ChartCandlestickSerie.h> +

+

+Inheritance diagram for CChartCandlestickSerie:
+
+ +

+ +CChartSerieBase< SChartCandlestickPoint > +CChartSerie + +
+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

CChartCandlestickSerie (CChartCtrl *pParent)
 Constructor.
~CChartCandlestickSerie ()
 Destructor.
bool IsPointOnSerie (const CPoint &screenPoint, unsigned &uIndex) const
 Tests if a certain screen point is on the series.
void AddPoint (double XVal, double Low, double High, double Open, double Close)
 Adds a new point in the series.
+void SetWidth (int Width)
 Sets the width (in pixels) of all candlestick points in the series.
+int GetWidth ()
 Returns the width (in pixels) of a point in the series.

Protected Member Functions

void DrawLegend (CDC *pDC, const CRect &rectBitmap) const
 Draws the legend icon for the series.
void Draw (CDC *pDC)
 Draws the most recent points of the series.
void DrawAll (CDC *pDC)
 Redraws the full series.
+


Detailed Description

+Specialization of a CChartSerieBase to display a candlestick series. +

+Each point in the series has an X value (the time), a high value (the highest market price), a low value (the lowest market price), an open value (the market price at the opening) and a close value (the market price at the closing).


Member Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void CChartCandlestickSerie::AddPoint (double  XVal,
double  Low,
double  High,
double  Open,
double  Close 
)
+
+
+ +

+Adds a new point in the series. +

+

Parameters:
+ + + + + + +
XVal The X value of the point (the time)
Low The lowest market price
High The highest market price
Open The market price at the opening
Close The market price at the closing
+
+ +
+

+ +

+
+ + + + + + + + + +
void CChartCandlestickSerie::Draw (CDC *  pDC  )  [protected, virtual]
+
+
+ +

+Draws the most recent points of the series. +

+This function should only draw the points that were not previously drawn.

Parameters:
+ + +
pDC The device context used to draw
+
+ +

Implements CChartSerie.

+ +
+

+ +

+
+ + + + + + + + + +
void CChartCandlestickSerie::DrawAll (CDC *  pDC  )  [protected, virtual]
+
+
+ +

+Redraws the full series. +

+

Parameters:
+ + +
pDC The device context used to draw
+
+ +

Implements CChartSerie.

+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartCandlestickSerie::DrawLegend (CDC *  pDC,
const CRect &  rectBitmap 
) const [protected, virtual]
+
+
+ +

+Draws the legend icon for the series. +

+

Parameters:
+ + + +
pDC The device context used to draw
rectBitmap The rectangle in which to draw the legend icon
+
+ +

Implements CChartSerie.

+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
bool CChartCandlestickSerie::IsPointOnSerie (const CPoint &  screenPoint,
unsigned &  uIndex 
) const [virtual]
+
+
+ +

+Tests if a certain screen point is on the series. +

+

Parameters:
+ + + +
screenPoint The screen point to test
uIndex If the point is close to a specific point of the series, its index is stored here.
+
+
Returns:
true if the point is on the series
+ +

Implements CChartSerie.

+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartCandlestickSerie.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartCandlestickSerie.cpp
+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_candlestick_serie.png b/ChartDemo/Doc/html/class_c_chart_candlestick_serie.png new file mode 100644 index 0000000000000000000000000000000000000000..2b2edcf8fe6ceb7243300f0bb902b47f3e2546e9 GIT binary patch literal 875 zcmeAS@N?(olHy`uVBq!ia0y~yU<9!{SeSw2+gCg00x5|ApAgso|NjG-|NkGDKR;mt zkOjsE4jiaH^#2Kv%UBZR7tG-B>_!>`12dzii(^Q|oVPQhi=HU(xSsXj*ITBrsd*;v z+3@%EoXsi^9&OqEEAdp?vJ&mW9K|CWD?%)z>dr5C8on#;zTd?sA{W#}WHgsb2%B@C zOwP3FZu%5ZY4A$p$;ZhL?UyGgpERFSS;VK|w)Lrq;pSQAmYmR3n92M1Dog0)nIcu* zW;rHZC7i8mLZqizNO|@w50+rQdNga<_R^gGKMO31-FAI;N^2?2Jyj{Va>l*BAMfYQ zef(5pLa>7$W37I8JXE~U#9=-my%=C~E_feJAmo*iZH_Txw z;sV-;#>ikfdiB3UpzkMn)#WRI3N+@0dsw~;u|1Nes=eb|-3sZ*tCI!WZ?TG;*IrW1 z8oce2>~|6A{e6qdZfwcdj9W1wE5B0ZO4AOtF0X|e&s)9BO$*;Di>mTEneuInkPom~ zGhv&Rnm8R;}M>}`dnfAqr}!L&w{O`(l$Nx4);2{)z6i6gI(2C zm#B!WbA{8B_B)+QJ-8`m<^|@)w*=OE=uUz@& zv8uY|^)=<_Lx1IV#`rN>vH~McM+6jxY&94E*xye(ZtAL9%-3b9HM2OtXOq=jtRV*u zOSga{l3Ug=-+Qv6DcHo4^$VA4+#&A{ZJXws?~>OnG+AuRv*<)&i^3O?tlJA$$eO)% z*0{EG&&65y^_QzW*^{B}**`<2?Z)*9`OZ^jEZow*VA@2Hz(wqmYi~5o?5f>5zh + +ChartDemo: Member List + + + + + +
+

CChartCrossHairCursor Member List

This is the complete list of members for CChartCrossHairCursor, including all inherited members.

+ + + + + + + + + + + + + + + + +
CChartCursor(CChartCtrl *pParent)CChartCursor [protected]
CursorMoved(double newXValue, double newYValue)CChartCursor [protected]
Draw(CDC *pDC)CChartCrossHairCursor [protected, virtual]
GetCursorId() const CChartCursor [inline]
m_colCursorCChartCursor [protected]
m_lstListenersCChartCursor [protected]
m_pParentCtrlCChartCursor [protected]
m_uCursorIdCChartCursor [protected]
m_uNextFreeIdCChartCursor [protected, static]
OnMouseButtonDown(CPoint)CChartCursor [inline, protected, virtual]
OnMouseButtonUp(CPoint)CChartCursor [inline, protected, virtual]
OnMouseMove(CPoint mousePoint)CChartCrossHairCursor [protected, virtual]
RegisterListener(CChartCursorListener *pListener)CChartCursor
SetColor(COLORREF cursorColor)CChartCursor
TListenerList typedef (defined in CChartCursor)CChartCursor [protected]
~CChartCursor()CChartCursor [protected, virtual]

+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_cross_hair_cursor.html b/ChartDemo/Doc/html/class_c_chart_cross_hair_cursor.html new file mode 100644 index 0000000..1e4c495 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_cross_hair_cursor.html @@ -0,0 +1,65 @@ + + +ChartDemo: CChartCrossHairCursor Class Reference + + + + + +
+

CChartCrossHairCursor Class Reference

Specialization of a CChartCursor class for a cross-hair cursor. +More... +

+#include <ChartCrossHairCursor.h> +

+

+Inheritance diagram for CChartCrossHairCursor:
+
+ +

+ +CChartCursor + +
+ +

+List of all members. + + + + + + + + +

Protected Member Functions

+void OnMouseMove (CPoint mousePoint)
 Called when the mouse is moved over the plot area.
+void Draw (CDC *pDC)
 Draws the cursor.
+


Detailed Description

+Specialization of a CChartCursor class for a cross-hair cursor. +

+A cross-hair cursor is a simple cross displayed in the plotting area. The cursor moves along with the mouse (but stay within the bounds of the plot area).
+ To create a cross-hair cursor, call the CreateCrossHairCursor from the CChartCtrl class.


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartCrossHairCursor.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartCrossHairCursor.cpp
+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_cross_hair_cursor.png b/ChartDemo/Doc/html/class_c_chart_cross_hair_cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..c28da378a593081900906ca7c1df6eb3ea479824 GIT binary patch literal 468 zcmV;_0W1EAP)yX`! zrTs4IZM`CDU2hjeU9*FM3RIv16{tY{R}@b(pjpZ>P$yByq^*=uHS$412OFxy z_G(2Xm+Neg+Rl}3&`YZ^grS2(UO2hR2Eh|A{l^K^Uq;P)d3^zmTN2yPWI{Rs0000< KMNUMnLSTZ2R>wX7 literal 0 HcmV?d00001 diff --git a/ChartDemo/Doc/html/class_c_chart_ctrl-members.html b/ChartDemo/Doc/html/class_c_chart_ctrl-members.html new file mode 100644 index 0000000..39d5ffd --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_ctrl-members.html @@ -0,0 +1,109 @@ + + +ChartDemo: Member List + + + + + +
+

CChartCtrl Member List

This is the complete list of members for CChartCtrl, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttachCustomAxis(CChartAxis *pAxis, EAxisPos axisPos)CChartCtrl
AttachCustomCursor(CChartCursor *pCursor)CChartCtrl
AttachCustomSerie(CChartSerie *pNewSeries, bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)CChartCtrl
BottomAxis enum value (defined in CChartCtrl)CChartCtrl
CChartCtrl()CChartCtrl
Create(CWnd *pParentWnd, const RECT &rect, UINT nID, DWORD dwStyle=WS_VISIBLE)CChartCtrl
CreateBarSerie(bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)CChartCtrl
CreateCandlestickSerie(bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)CChartCtrl
CreateCrossHairCursor(bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)CChartCtrl
CreateDateTimeAxis(EAxisPos axisPos)CChartCtrl
CreateDragLineCursor(EAxisPos relatedAxis)CChartCtrl
CreateGanttSerie(bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)CChartCtrl
CreateLineSerie(bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)CChartCtrl
CreateLogarithmicAxis(EAxisPos axisPos)CChartCtrl
CreatePointsSerie(bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)CChartCtrl
CreateStandardAxis(EAxisPos axisPos)CChartCtrl
CreateSurfaceSerie(bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)CChartCtrl
DateToValue(const COleDateTime &Date)CChartCtrl [static]
DrawBackground(CDC *pDC, CRect ChartRect) (defined in CChartCtrl)CChartCtrl [protected, virtual]
DrawChart(CDC *pDC, CRect ChartRect) (defined in CChartCtrl)CChartCtrl [protected, virtual]
EAxisPos enum nameCChartCtrl
EnableRefresh(bool bEnable)CChartCtrl
GetAxis(EAxisPos axisPos) const CChartCtrl [inline]
GetBackColor() const CChartCtrl [inline]
GetBorderColor() const CChartCtrl [inline]
GetBottomAxis() const (defined in CChartCtrl)CChartCtrl
GetDC()CChartCtrl
GetEdgeType() const CChartCtrl [inline]
GetLeftAxis() const (defined in CChartCtrl)CChartCtrl
GetLegend() const CChartCtrl [inline]
GetNextSerie()CChartCtrl
GetPanEnabled() const CChartCtrl [inline]
GetPlottingRect() const CChartCtrl [inline]
GetRightAxis() const (defined in CChartCtrl)CChartCtrl
GetSerie(unsigned uSerieId) const CChartCtrl
GetSeriesCount() const CChartCtrl
GetTitle() const CChartCtrl [inline]
GetTopAxis() const (defined in CChartCtrl)CChartCtrl
GetZoomEnabled() const CChartCtrl [inline]
GetZoomRectColor() const CChartCtrl [inline]
GoToFirstSerie()CChartCtrl
LeftAxis enum value (defined in CChartCtrl)CChartCtrl
OnBeginPrinting(CDC *pDC, CPrintInfo *pInfo) (defined in CChartCtrl)CChartCtrl [protected, virtual]
OnEndPrinting(CDC *pDC, CPrintInfo *pInfo) (defined in CChartCtrl)CChartCtrl [protected, virtual]
OnEraseBkgnd(CDC *pDC) (defined in CChartCtrl)CChartCtrl [protected]
OnHScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar) (defined in CChartCtrl)CChartCtrl [protected]
OnLButtonDblClk(UINT nFlags, CPoint point) (defined in CChartCtrl)CChartCtrl [protected]
OnLButtonDown(UINT nFlags, CPoint point) (defined in CChartCtrl)CChartCtrl [protected]
OnLButtonUp(UINT nFlags, CPoint point) (defined in CChartCtrl)CChartCtrl [protected]
OnMouseMove(UINT nFlags, CPoint point) (defined in CChartCtrl)CChartCtrl [protected]
OnPaint() (defined in CChartCtrl)CChartCtrl [protected]
OnPrint(CDC *pDC, CPrintInfo *pInfo) (defined in CChartCtrl)CChartCtrl [protected, virtual]
OnRButtonDblClk(UINT nFlags, CPoint point) (defined in CChartCtrl)CChartCtrl [protected]
OnRButtonDown(UINT nFlags, CPoint point) (defined in CChartCtrl)CChartCtrl [protected]
OnRButtonUp(UINT nFlags, CPoint point) (defined in CChartCtrl)CChartCtrl [protected]
OnSize(UINT nType, int cx, int cy) (defined in CChartCtrl)CChartCtrl [protected]
OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar) (defined in CChartCtrl)CChartCtrl [protected]
Print(const TChartString &strTitle, CPrintDialog *pPrntDialog=NULL)CChartCtrl [virtual]
RefreshCtrl()CChartCtrl
RefreshScreenAutoAxes()CChartCtrl
RegisterMouseListener(CChartMouseListener *pMouseListener)CChartCtrl [inline]
RemoveAllSeries()CChartCtrl
RemoveCursor(unsigned cursorId)CChartCtrl
RemoveSerie(unsigned uSerieId)CChartCtrl
RightAxis enum value (defined in CChartCtrl)CChartCtrl
SetBackColor(COLORREF NewCol)CChartCtrl [inline]
SetBackGradient(COLORREF Col1, COLORREF Col2, EGradientType GradientType)CChartCtrl
SetBorderColor(COLORREF NewCol)CChartCtrl [inline]
SetEdgeType(UINT NewEdge)CChartCtrl [inline]
SetPanEnabled(bool bEnabled)CChartCtrl [inline]
SetZoomEnabled(bool bEnabled)CChartCtrl [inline]
SetZoomRectColor(COLORREF NewCol)CChartCtrl [inline]
ShowMouseCursor(bool bShow)CChartCtrl
TopAxis enum value (defined in CChartCtrl)CChartCtrl
UndoPanZoom()CChartCtrl
ValueToDate(double Value)CChartCtrl [static]
~CChartCtrl()CChartCtrl [virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_ctrl.html b/ChartDemo/Doc/html/class_c_chart_ctrl.html new file mode 100644 index 0000000..976aa8f --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_ctrl.html @@ -0,0 +1,1206 @@ + + +ChartDemo: CChartCtrl Class Reference + + + + + +
+

CChartCtrl Class Reference

The main chart control class. +More... +

+#include <ChartCtrl.h> +

+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Types

enum  EAxisPos { LeftAxis = 0, +BottomAxis, +RightAxis, +TopAxis + }
 An enumeration of the different axis positions.

Public Member Functions

CDC * GetDC ()
 Retrieves de device context.
+CRect GetPlottingRect () const
 Retrieves the plotting rectangle.
+CChartLegendGetLegend () const
 Returns a pointer to the legend object.
+CChartTitleGetTitle () const
 Returns a pointer to the title object.
CChartStandardAxisCreateStandardAxis (EAxisPos axisPos)
 Create and attach a standard axis to the control.
CChartLogarithmicAxisCreateLogarithmicAxis (EAxisPos axisPos)
 Create and attach a logarithmic axis to the control.
CChartDateTimeAxisCreateDateTimeAxis (EAxisPos axisPos)
 Create and attach a date/time axis to the control.
void AttachCustomAxis (CChartAxis *pAxis, EAxisPos axisPos)
 Attach a custom axis to the control.
CChartPointsSerieCreatePointsSerie (bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)
 Create and attach a point series to the control.
CChartLineSerieCreateLineSerie (bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)
 Create and attach a line series to the control.
CChartSurfaceSerieCreateSurfaceSerie (bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)
 Create and attach a surface series to the control.
CChartBarSerieCreateBarSerie (bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)
 Create and attach a bar series to the control.
CChartCandlestickSerieCreateCandlestickSerie (bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)
 Create and attach a candlestick series to the control.
CChartGanttSerieCreateGanttSerie (bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)
 Create and attach a gantt series to the control.
void AttachCustomSerie (CChartSerie *pNewSeries, bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)
 Attaches a custom series to the chart.
CChartSerieGetSerie (unsigned uSerieId) const
 Retrieves a specific series from the chart.
void RemoveSerie (unsigned uSerieId)
 Removes a specific series from the chart.
+void RemoveAllSeries ()
 Removes all the series from the chart.
+size_t GetSeriesCount () const
 Returns the number of series in the chart.
CChartCrossHairCursorCreateCrossHairCursor (bool bSecondaryHorizAxis=false, bool bSecondaryVertAxis=false)
 Create and attach a cross-hair cursor to the control.
CChartDragLineCursorCreateDragLineCursor (EAxisPos relatedAxis)
 Create and attach a drag-line cursor to the control.
void AttachCustomCursor (CChartCursor *pCursor)
 Attach a custom cursor to the control.
void RemoveCursor (unsigned cursorId)
 Removes a cursor with a specific Id from the control.
+void ShowMouseCursor (bool bShow)
 Shows/hides the mouse cursor when it is over the plotting area.
+CChartAxisGetBottomAxis () const
+CChartAxisGetLeftAxis () const
+CChartAxisGetTopAxis () const
+CChartAxisGetRightAxis () const
CChartAxisGetAxis (EAxisPos axisPos) const
 Returns a specific axis attached to the control.
+UINT GetEdgeType () const
 Returns the type of the edge used as border.
void SetEdgeType (UINT NewEdge)
 Sets the edge type.
+COLORREF GetBackColor () const
 Returns the background color.
+void SetBackColor (COLORREF NewCol)
 Sets the background color.
+COLORREF GetBorderColor () const
 Returns the color of the plotting area's border.
+void SetBorderColor (COLORREF NewCol)
 Sets the color of the plotting area's border.
+COLORREF GetZoomRectColor () const
 Returns the color of the zoom rectangle.
+void SetZoomRectColor (COLORREF NewCol)
 Sets the color of the zoom rectangle.
void SetBackGradient (COLORREF Col1, COLORREF Col2, EGradientType GradientType)
 Sets a gradient background.
+void SetPanEnabled (bool bEnabled)
 Enables/disables the pan feature.
+bool GetPanEnabled () const
 Returns true if the pan feature is enabled.
+void SetZoomEnabled (bool bEnabled)
 Enables/disables the zoom feature.
+bool GetZoomEnabled () const
 Returns true if the zoom feature is enabled.
+void UndoPanZoom ()
 Undo all pan and zoom operations that were done on the chart.
void RefreshCtrl ()
 Forces a refresh of the control.
void EnableRefresh (bool bEnable)
 Enables/disables the refresh of the control.
int Create (CWnd *pParentWnd, const RECT &rect, UINT nID, DWORD dwStyle=WS_VISIBLE)
 Creates the control dynamically.
virtual void Print (const TChartString &strTitle, CPrintDialog *pPrntDialog=NULL)
 Print the chart.
CChartCtrl ()
 Default constructor.
+virtual ~CChartCtrl ()
 Default destructor.
void RegisterMouseListener (CChartMouseListener *pMouseListener)
 Register a mouse listener with the control.
void GoToFirstSerie ()
 Tell the control to set the current series to the first series.
CChartSerieGetNextSerie ()
 Returns the next series in the control.
+void RefreshScreenAutoAxes ()
 Refreshes all the axes which are automatic for the screen.

Static Public Member Functions

+static double DateToValue (const COleDateTime &Date)
 Helper function to convert a date to a double value.
+static COleDateTime ValueToDate (double Value)
 Helper function to convert a double value to a date.

Protected Member Functions

+afx_msg void OnPaint ()
+afx_msg BOOL OnEraseBkgnd (CDC *pDC)
+afx_msg void OnSize (UINT nType, int cx, int cy)
+afx_msg void OnMouseMove (UINT nFlags, CPoint point)
+afx_msg void OnLButtonDown (UINT nFlags, CPoint point)
+afx_msg void OnLButtonUp (UINT nFlags, CPoint point)
+afx_msg void OnLButtonDblClk (UINT nFlags, CPoint point)
+afx_msg void OnRButtonDown (UINT nFlags, CPoint point)
+afx_msg void OnRButtonUp (UINT nFlags, CPoint point)
+afx_msg void OnRButtonDblClk (UINT nFlags, CPoint point)
+afx_msg void OnHScroll (UINT nSBCode, UINT nPos, CScrollBar *pScrollBar)
+afx_msg void OnVScroll (UINT nSBCode, UINT nPos, CScrollBar *pScrollBar)
+virtual void OnBeginPrinting (CDC *pDC, CPrintInfo *pInfo)
+virtual void OnPrint (CDC *pDC, CPrintInfo *pInfo)
+virtual void OnEndPrinting (CDC *pDC, CPrintInfo *pInfo)
+virtual void DrawChart (CDC *pDC, CRect ChartRect)
+virtual void DrawBackground (CDC *pDC, CRect ChartRect)
+


Detailed Description

+The main chart control class.

Member Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
void CChartCtrl::AttachCustomAxis (CChartAxis pAxis,
EAxisPos  axisPos 
)
+
+
+ +

+Attach a custom axis to the control. +

+This function takes ownership of the axis pointer, so you must not destroy it. If the axis is alread attached to a chart control (even this one), the function will fail with an assertion. This function should be used only when you want to provide a custom axis to the control, otherwise you should use the AttachStandardAxis, AttachLogarithmicAxis and AttachDateTimeAxis instead.

Parameters:
+ + + +
pAxis The axis to attach to the control.
axisPos The position of the axis. This value can be:
    +
  • LeftAxis
  • BottomAxis
  • RightAxis
  • TopAxis
+
+
+ +
+

+ +

+
+ + + + + + + + + +
void CChartCtrl::AttachCustomCursor (CChartCursor pCursor  ) 
+
+
+ +

+Attach a custom cursor to the control. +

+You should only use this function if you want to attach a custom cursor to the control. Otherwise, you should use the CreateXXXCursor helper functions.

Parameters:
+ + +
pCursor The custom cursor to be attached to the control.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void CChartCtrl::AttachCustomSerie (CChartSerie pNewSeries,
bool  bSecondaryHorizAxis = false,
bool  bSecondaryVertAxis = false 
)
+
+
+ +

+Attaches a custom series to the chart. +

+You should only use this function if you want to attach a custom series to the control. Otherwise, you should use the CreateXXXSerie helper functions. The function will assert if the associated axes are not attached to the control.

Parameters:
+ + + + +
pNewSeries The new series to be added. The control will take ownership of the pointer, so dont't delete it yourself.
bSecondaryHorizAxis Specifies if the associated horizontal axis is secondary or not. If this value is false, the associated horizontal axis is the bottom axis, otherwise it is the top axis.
bSecondaryVertAxis Specifies if the associated vertical axis is secondary or not. If this value is false, the associated vertical axis is the left axis, otherwise it is the right axis.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int CChartCtrl::Create (CWnd *  pParentWnd,
const RECT &  rect,
UINT  nID,
DWORD  dwStyle = WS_VISIBLE 
)
+
+
+ +

+Creates the control dynamically. +

+

Parameters:
+ + + + + +
pParentWnd Parent window of the control
rect Position of the control
nID ID of the control
dwStyle Style of the control
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
CChartBarSerie * CChartCtrl::CreateBarSerie (bool  bSecondaryHorizAxis = false,
bool  bSecondaryVertAxis = false 
)
+
+
+ +

+Create and attach a bar series to the control. +

+

Parameters:
+ + + +
bSecondaryHorizAxis Specifies if the horizontal axis is the secondary axis or not.
bSecondaryVertAxis Specifies if the vertical axis is the secondary axis or not.
+
+
Returns:
The created chart bar series.
+
Remarks:
The function will assert if the associated axes are not attached to the control.
+
See also:
AttachCustomSerie for more info about the parameters of the function.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
CChartCandlestickSerie * CChartCtrl::CreateCandlestickSerie (bool  bSecondaryHorizAxis = false,
bool  bSecondaryVertAxis = false 
)
+
+
+ +

+Create and attach a candlestick series to the control. +

+

Parameters:
+ + + +
bSecondaryHorizAxis Specifies if the horizontal axis is the secondary axis or not.
bSecondaryVertAxis Specifies if the vertical axis is the secondary axis or not.
+
+
Returns:
The created chart candlestick series.
+
Remarks:
The function will assert if the associated axes are not attached to the control.
+
See also:
AttachCustomSerie for more info about the parameters of the function.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
CChartCrossHairCursor * CChartCtrl::CreateCrossHairCursor (bool  bSecondaryHorizAxis = false,
bool  bSecondaryVertAxis = false 
)
+
+
+ +

+Create and attach a cross-hair cursor to the control. +

+A cross-hair cursor display a cross on the control and move accordingly to the mouse. It is attached to an horizontal and a vertical axis.

Parameters:
+ + + +
bSecondaryHorizAxis Specifies if the horizontal axis is the secondary axis or not.
bSecondaryVertAxis Specifies if the vertical axis is the secondary axis or not.
+
+
Returns:
The created cross-hair cursor.
+
Remarks:
The function will assert if the associated axes are not attached to the control.
+ +
+

+ +

+
+ + + + + + + + + +
CChartDateTimeAxis * CChartCtrl::CreateDateTimeAxis (EAxisPos  axisPos  ) 
+
+
+ +

+Create and attach a date/time axis to the control. +

+

Parameters:
+ + +
axisPos The position of the axis.
+
+
Returns:
The created date/time axis.
+ +
+

+ +

+
+ + + + + + + + + +
CChartDragLineCursor * CChartCtrl::CreateDragLineCursor (EAxisPos  relatedAxis  ) 
+
+
+ +

+Create and attach a drag-line cursor to the control. +

+A drag-line cursor is a simple line (horizontal or vertical) that can be dragged with the mouse by clicking on it. It is attached to a specific axis.

Parameters:
+ + +
relatedAxis The axis position to which the cursor is attached to.
+
+
Returns:
The created drag-line cursor.
+
Remarks:
The function will assert if the associated axis is not attached to the control.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
CChartGanttSerie * CChartCtrl::CreateGanttSerie (bool  bSecondaryHorizAxis = false,
bool  bSecondaryVertAxis = false 
)
+
+
+ +

+Create and attach a gantt series to the control. +

+

Parameters:
+ + + +
bSecondaryHorizAxis Specifies if the horizontal axis is the secondary axis or not.
bSecondaryVertAxis Specifies if the vertical axis is the secondary axis or not.
+
+
Returns:
The created chart gantt series.
+
Remarks:
The function will assert if the associated axes are not attached to the control.
+
See also:
AttachCustomSerie for more info about the parameters of the function.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
CChartLineSerie * CChartCtrl::CreateLineSerie (bool  bSecondaryHorizAxis = false,
bool  bSecondaryVertAxis = false 
)
+
+
+ +

+Create and attach a line series to the control. +

+The function will assert if the associated axes are not attached to the control.

Parameters:
+ + + +
bSecondaryHorizAxis Specifies if the horizontal axis is the secondary axis or not.
bSecondaryVertAxis Specifies if the vertical axis is the secondary axis or not.
+
+
Returns:
The created chart line series.
+
Remarks:
The function will assert if the associated axes are not attached to the control.
+
See also:
AttachCustomSerie for more info about the parameters of the function.
+ +
+

+ +

+
+ + + + + + + + + +
CChartLogarithmicAxis * CChartCtrl::CreateLogarithmicAxis (EAxisPos  axisPos  ) 
+
+
+ +

+Create and attach a logarithmic axis to the control. +

+

Parameters:
+ + +
axisPos The position of the axis.
+
+
Returns:
The created logarithmic axis.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
CChartPointsSerie * CChartCtrl::CreatePointsSerie (bool  bSecondaryHorizAxis = false,
bool  bSecondaryVertAxis = false 
)
+
+
+ +

+Create and attach a point series to the control. +

+

Parameters:
+ + + +
bSecondaryHorizAxis Specifies if the horizontal axis is the secondary axis or not.
bSecondaryVertAxis Specifies if the vertical axis is the secondary axis or not.
+
+
Returns:
The created chart point series.
+
Remarks:
The function will assert if the associated axes are not attached to the control.
+
See also:
AttachCustomSerie for more info about the parameters of the function.
+ +
+

+ +

+
+ + + + + + + + + +
CChartStandardAxis * CChartCtrl::CreateStandardAxis (EAxisPos  axisPos  ) 
+
+
+ +

+Create and attach a standard axis to the control. +

+

Parameters:
+ + +
axisPos The position of the axis.
+
+
Returns:
The created standard axis.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
CChartSurfaceSerie * CChartCtrl::CreateSurfaceSerie (bool  bSecondaryHorizAxis = false,
bool  bSecondaryVertAxis = false 
)
+
+
+ +

+Create and attach a surface series to the control. +

+The function will assert if the associated axes are not attached to the control.

Parameters:
+ + + +
bSecondaryHorizAxis Specifies if the horizontal axis is the secondary axis or not.
bSecondaryVertAxis Specifies if the vertical axis is the secondary axis or not.
+
+
Returns:
The created chart surface series.
+
Remarks:
The function will assert if the associated axes are not attached to the control.
+
See also:
AttachCustomSerie for more info about the parameters of the function.
+ +
+

+ +

+
+ + + + + + + + + +
void CChartCtrl::EnableRefresh (bool  bEnable  ) 
+
+
+ +

+Enables/disables the refresh of the control. +

+This function is used when several settings have to be changed at the same time on the control. This way we can avoid refreshing the control when it is not needed.

Parameters:
+ + +
bEnable false to disable the refresh and true to re-enable the refresh.
+
+ +
+

+ +

+
+ + + + + + + + + +
CChartAxis* CChartCtrl::GetAxis (EAxisPos  axisPos  )  const [inline]
+
+
+ +

+Returns a specific axis attached to the control. +

+If the specified axis does not exist, NULL is returned.

Parameters:
+ + +
axisPos The axis position (left, bottom, right or top).
+
+ +
+

+ +

+
+ + + + + + + + +
CDC * CChartCtrl::GetDC (  ) 
+
+
+ +

+Retrieves de device context. +

+This function is used for internal purposes only. +

+

+ +

+
+ + + + + + + + +
CChartSerie * CChartCtrl::GetNextSerie (  ) 
+
+
+ +

+Returns the next series in the control. +

+This function is used with the GoToFirstSerie to iterate over all series in the control. First call GoToFirstSerie and then call this function until it returns NULL to iterate over all series. Warning: calling this function without calling GoToFirstSerie before might lead to unpredicted results. The same if you add or remove series between the call to GetFirstSerie and the call to GetNextSerie.

Returns:
the next series or NULL if we already are at the last series.
+ +
+

+ +

+
+ + + + + + + + + +
CChartSerie* CChartCtrl::GetSerie (unsigned  uSerieId  )  const
+
+
+ +

+Retrieves a specific series from the chart. +

+

Parameters:
+ + +
uSerieId The Id of the series to retrieve
+
+
Returns:
The series or NULL if uSerieId is not attributed.
+ +
+

+ +

+
+ + + + + + + + +
void CChartCtrl::GoToFirstSerie (  ) 
+
+
+ +

+Tell the control to set the current series to the first series. +

+This function is used with the GetNextSerie to iterate over all series in the control. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartCtrl::Print (const TChartString &  strTitle,
CPrintDialog *  pPrntDialog = NULL 
) [virtual]
+
+
+ +

+Print the chart. +

+

Parameters:
+ + + +
strTitle The title of the print document.
pPrntDialog A pointer to a CPrintDialog. If NULL is passed, the default print dialog will be displayed.
+
+ +
+

+ +

+
+ + + + + + + + +
void CChartCtrl::RefreshCtrl (  ) 
+
+
+ +

+Forces a refresh of the control. +

+This function is used for internal purposes. +

+

+ +

+
+ + + + + + + + + +
void CChartCtrl::RegisterMouseListener (CChartMouseListener pMouseListener  )  [inline]
+
+
+ +

+Register a mouse listener with the control. +

+This listener will be notified each time a mouse event occurs on the control.

Parameters:
+ + +
pMouseListener The mouse listener to register with this control.
+
+ +
+

+ +

+
+ + + + + + + + + +
void CChartCtrl::RemoveCursor (unsigned  cursorId  ) 
+
+
+ +

+Removes a cursor with a specific Id from the control. +

+The cursor Id can be retrieved on through the CChartCursor::GetCursorId function.

Parameters:
+ + +
cursorId The Id of the cursor to remove from the control.
+
+ +
+

+ +

+
+ + + + + + + + + +
void CChartCtrl::RemoveSerie (unsigned  uSerieId  ) 
+
+
+ +

+Removes a specific series from the chart. +

+

Parameters:
+ + +
uSerieId The Id of the series to be removed.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void CChartCtrl::SetBackGradient (COLORREF  Col1,
COLORREF  Col2,
EGradientType  GradientType 
)
+
+
+ +

+Sets a gradient background. +

+

Parameters:
+ + + + +
Col1 The first gradient color
Col2 The second gradient color
GradientType The type of gradient used from Col1 to Col2. It can take the following values:
    +
  • gtHorizontal: a simple left-to-right gradient, from Col1 to Col2.
  • gtVertical: a simple top-to-bottom gradient, from Col1 to Col2.
  • gtHorizontalDouble: a left-to-middle-to-right gradient, with Col2 in the middle.
  • gtVerticalDouble: a top-to-middle-to-bottom gradient, with Col2 in the middle.
+
+
+ +
+

+ +

+
+ + + + + + + + + +
void CChartCtrl::SetEdgeType (UINT  NewEdge  )  [inline]
+
+
+ +

+Sets the edge type. +

+

Parameters:
+ + +
NewEdge The type of the edge. See the DrawEdge function in MSDN for a list of the different types.
+
+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartCtrl.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartCtrl.cpp
+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_cursor-members.html b/ChartDemo/Doc/html/class_c_chart_cursor-members.html new file mode 100644 index 0000000..4996412 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_cursor-members.html @@ -0,0 +1,48 @@ + + +ChartDemo: Member List + + + + + +
+

CChartCursor Member List

This is the complete list of members for CChartCursor, including all inherited members.

+ + + + + + + + + + + + + + + + +
CChartCursor(CChartCtrl *pParent)CChartCursor [protected]
CursorMoved(double newXValue, double newYValue)CChartCursor [protected]
Draw(CDC *pDC)=0CChartCursor [protected, pure virtual]
GetCursorId() const CChartCursor [inline]
m_colCursorCChartCursor [protected]
m_lstListenersCChartCursor [protected]
m_pParentCtrlCChartCursor [protected]
m_uCursorIdCChartCursor [protected]
m_uNextFreeIdCChartCursor [protected, static]
OnMouseButtonDown(CPoint)CChartCursor [inline, protected, virtual]
OnMouseButtonUp(CPoint)CChartCursor [inline, protected, virtual]
OnMouseMove(CPoint mousePoint)=0CChartCursor [protected, pure virtual]
RegisterListener(CChartCursorListener *pListener)CChartCursor
SetColor(COLORREF cursorColor)CChartCursor
TListenerList typedef (defined in CChartCursor)CChartCursor [protected]
~CChartCursor()CChartCursor [protected, virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_cursor.html b/ChartDemo/Doc/html/class_c_chart_cursor.html new file mode 100644 index 0000000..0746e40 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_cursor.html @@ -0,0 +1,225 @@ + + +ChartDemo: CChartCursor Class Reference + + + + + +
+

CChartCursor Class Reference

Base class for cursors which can be added to the chart control. +More... +

+#include <ChartCursor.h> +

+

+Inheritance diagram for CChartCursor:
+
+ +

+ +CChartCrossHairCursor +CChartDragLineCursor + +
+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

+void SetColor (COLORREF cursorColor)
 Sets the cursor color.
+unsigned GetCursorId () const
 Retrieves the cursor Id.
+void RegisterListener (CChartCursorListener *pListener)
 Registers a cursor listener with this cursor.

Protected Types

+typedef std::list
+< CChartCursorListener * > 
TListenerList

Protected Member Functions

CChartCursor (CChartCtrl *pParent)
 Default constructor.
+virtual ~CChartCursor ()
 Default destructor.
virtual void OnMouseMove (CPoint mousePoint)=0
 Pure virtual function that is called when the mouse moved on the plot area.
virtual void OnMouseButtonDown (CPoint)
 Virtual function that is called when the left mouse button is pressed.
virtual void OnMouseButtonUp (CPoint)
 Virtual function that is called when the left mouse button is released.
+virtual void Draw (CDC *pDC)=0
 Pure virtual function that draws the cursor.
void CursorMoved (double newXValue, double newYValue)
 Function that is called by the child classes when the cursor has been moved.

Protected Attributes

+COLORREF m_colCursor
 The color of the cursor.
+CChartCtrlm_pParentCtrl
 The parent charting control.
+unsigned m_uCursorId
 The Id of this curosr.
+TListenerList m_lstListeners
 List of all listeners registered with this cursor.

Static Protected Attributes

+static unsigned m_uNextFreeId = 0
 Static variable holding the next free cursor Id.
+


Detailed Description

+Base class for cursors which can be added to the chart control. +

+This class must be overriden for specific cursor types. This is already done for a cross-hair cursor and a dragline cursor. Each cursor is assigned an Id when it is added to the control.


Member Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
void CChartCursor::CursorMoved (double  newXValue,
double  newYValue 
) [protected]
+
+
+ +

+Function that is called by the child classes when the cursor has been moved. +

+This will notify all the listeners registered with the cursor. +

+

+ +

+
+ + + + + + + + + +
virtual void CChartCursor::OnMouseButtonDown (CPoint   )  [inline, protected, virtual]
+
+
+ +

+Virtual function that is called when the left mouse button is pressed. +

+This function can be overriden by child classes to take appropriate actions on the mouse click event. +

Reimplemented in CChartDragLineCursor.

+ +
+

+ +

+
+ + + + + + + + + +
virtual void CChartCursor::OnMouseButtonUp (CPoint   )  [inline, protected, virtual]
+
+
+ +

+Virtual function that is called when the left mouse button is released. +

+This function can be overriden by child classes to take appropriate actions on the mouse click event. +

Reimplemented in CChartDragLineCursor.

+ +
+

+ +

+
+ + + + + + + + + +
virtual void CChartCursor::OnMouseMove (CPoint  mousePoint  )  [protected, pure virtual]
+
+
+ +

+Pure virtual function that is called when the mouse moved on the plot area. +

+This function must be overriden by child classes to take appropriate actions on the mouse move event. +

Implemented in CChartCrossHairCursor, and CChartDragLineCursor.

+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartCursor.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartCursor.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_cursor.png b/ChartDemo/Doc/html/class_c_chart_cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..9ffcbdbb4c6f12386ee4812c5aebcc992d20d254 GIT binary patch literal 750 zcmeAS@N?(olHy`uVBq!ia0y~yU^D`<16Y`WWX9qr!azzQz$e7@|Ns9$=Kuc(=Fd-< z0AzvjfddDs5B+}vEalY(fD?HZr&3Gp0>mD{~fz?;0JdK6U@b=TaR=5ciHOO<1l6^Gp2Hs{tRa)@r*eEgn)!6hT<{!}x$`w4C$ z+t=LPZKV0#vu5wi&bc=}1kRk<*SG)PnP+QwAB(h|Yx%hORr;A}la0@2Y)(o(8+PVV zq1B8`HEmy$vduRZ$xl9e=#>4e+%G)F#gdzK)zxQ&R&SmmDR}AQ?6ff3^M`Vxv`^bU z^GFZ=_Dp2+{~n-?r*mwk-K_Ydu=)7ERj<3YOU^AjT6{L{{bt^Gk2a>|ufLwtI=f=s z&F1n05C=k(`xsOwK9)^qb7?Ge5RqUff%^LR-)Y+D{`HBettu%Hy@p-eBUQ2S@HzodT3FDKhmm$w5YUs6>WEy^+ z1Co!k(l)D_zkB96??dKiW}Hj=nse#onak;E*7{d3AJn;%mwN1-vT?cO<}bI>KPN2P zT$#V^^Cu1Y<7=YQzfOtymZq4wZtJ-@*MjnFXK$@|!@Y6M=1W>TLrRTq&$lo9a#^e2 z^4s*iFJq!g9elF{r5}E)l C7h`My literal 0 HcmV?d00001 diff --git a/ChartDemo/Doc/html/class_c_chart_cursor_listener-members.html b/ChartDemo/Doc/html/class_c_chart_cursor_listener-members.html new file mode 100644 index 0000000..8066ef1 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_cursor_listener-members.html @@ -0,0 +1,35 @@ + + +ChartDemo: Member List + + + + + +
+

CChartCursorListener Member List

This is the complete list of members for CChartCursorListener, including all inherited members.

+ + + +
CChartCursorListener()CChartCursorListener
OnCursorMoved(CChartCursor *pCursor, double xValue, double yValue)=0CChartCursorListener [pure virtual]
~CChartCursorListener()CChartCursorListener [virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_cursor_listener.html b/ChartDemo/Doc/html/class_c_chart_cursor_listener.html new file mode 100644 index 0000000..6c62bfb --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_cursor_listener.html @@ -0,0 +1,103 @@ + + +ChartDemo: CChartCursorListener Class Reference + + + + + +
+

CChartCursorListener Class Reference

Interface to implement in order to be notified about a cursor movement. +More... +

+#include <ChartCursor.h> +

+ +

+List of all members. + + + + + + + + + + + +

Public Member Functions

CChartCursorListener ()
 Default constructor.
+virtual ~CChartCursorListener ()
 Destructor.
virtual void OnCursorMoved (CChartCursor *pCursor, double xValue, double yValue)=0
 Pure virtual function to implement in order to be notified about a cursor movement.
+


Detailed Description

+Interface to implement in order to be notified about a cursor movement. +

+This class must be overriden and registered with a CChartCursor by calling RegisterListener.


Member Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual void CChartCursorListener::OnCursorMoved (CChartCursor pCursor,
double  xValue,
double  yValue 
) [pure virtual]
+
+
+ +

+Pure virtual function to implement in order to be notified about a cursor movement. +

+Note that not all cursor types have an X and a Y value, in which case, only the relevant information is passed, the other value will be 0.

Parameters:
+ + + + +
pCursor The cursor which was moved
xValue The cursor xValue
yValue The cursor yValue
+
+ +
+

+


The documentation for this class was generated from the following file: +
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_date_time_axis-members.html b/ChartDemo/Doc/html/class_c_chart_date_time_axis-members.html new file mode 100644 index 0000000..59b14bd --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_date_time_axis-members.html @@ -0,0 +1,101 @@ + + +ChartDemo: Member List + + + + + +
+

CChartDateTimeAxis Member List

This is the complete list of members for CChartDateTimeAxis, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CChartAxis()CChartAxis
EAxisAutoModes enum nameCChartAxis
EnableScrollBar(bool bEnabled)CChartAxis
FullAutomatic enum valueCChartAxis
GetAutoHideScrollBar() const CChartAxis
GetAutomaticMode() const CChartAxis [inline]
GetAxisLenght() const CChartAxis [protected]
GetGrid() const CChartAxis [inline]
GetLabel() const CChartAxis [inline]
GetMinMax(double &Minimum, double &Maximum) const CChartAxis [inline]
GetPosition()CChartAxis
GetScrollbarSteps(int &iTotalSteps, int &iCurrentStep)CChartAxis [protected, virtual]
GetSeriesMinMax(double &Minimum, double &Maximum)CChartAxis [protected]
GetSeriesScreenMinMax(double &Minimum, double &Maximum)CChartAxis [protected]
GetTextColor() const CChartAxis [inline]
IsAutomatic() const CChartAxis [inline]
IsHorizontal() const CChartAxis [inline]
IsInverted() const CChartAxis [inline]
IsPointInside(const CPoint &screenPoint) const CChartAxis
IsVisible() const CChartAxis [inline]
m_AutoModeCChartAxis [protected]
m_AxisRectCChartAxis [protected]
m_bAutoTicksCChartAxis [protected]
m_bDiscreteCChartAxis [protected]
m_bIsHorizontalCChartAxis [protected]
m_bIsInvertedCChartAxis [protected]
m_bIsSecondaryCChartAxis [protected]
m_bIsVisibleCChartAxis [protected]
m_EndPosCChartAxis [protected]
m_MaxValueCChartAxis [protected]
m_MinValueCChartAxis [protected]
m_pParentCtrlCChartAxis [protected]
m_StartPosCChartAxis [protected]
m_UnzoomMaxCChartAxis [protected]
m_UnzoomMinCChartAxis [protected]
NotAutomatic enum valueCChartAxis
PanAxis(long PanStart, long PanEnd)CChartAxis [protected, virtual]
ScreenAutomatic enum valueCChartAxis
ScreenToValue(long ScreenVal) const CChartAxis [virtual]
ScrollBarEnabled() const CChartAxis [inline]
SetAutoHideScrollBar(bool bAutoHide)CChartAxis
SetAutomatic(bool bAutomatic)CChartAxis
SetAutomaticMode(EAxisAutoModes AutoMode)CChartAxis
SetAxisColor(COLORREF NewColor)CChartAxis
SetAxisToScrollStep(int iPreviousStep, int iCurrentStep, bool bScrollInverted)CChartAxis [protected, virtual]
SetDiscrete(bool bDiscrete)CChartAxis [virtual]
SetFont(int nPointSize, const TChartString &strFaceName)CChartAxis
SetInverted(bool bInverted)CChartAxis
SetMarginSize(bool bAuto, int iNewSize)CChartAxis
SetMinMax(double Minimum, double Maximum)CChartAxis
SetPanZoomEnabled(bool bEnabled)CChartAxis [inline]
SetReferenceTick(COleDateTime referenceTick)CChartDateTimeAxis
SetTextColor(COLORREF NewColor)CChartAxis
SetTickIncrement(bool bAuto, TimeInterval Interval, int Multiplier)CChartDateTimeAxis
SetTickLabelFormat(bool bAutomatic, const TChartString &strFormat)CChartDateTimeAxis
SetVisible(bool bVisible)CChartAxis
SetZoomLimit(double dLimit)CChartAxis [inline]
SetZoomMinMax(double Minimum, double Maximum)CChartAxis [protected, virtual]
tiDay enum value (defined in CChartDateTimeAxis)CChartDateTimeAxis
tiHour enum value (defined in CChartDateTimeAxis)CChartDateTimeAxis
TimeInterval enum nameCChartDateTimeAxis
tiMinute enum value (defined in CChartDateTimeAxis)CChartDateTimeAxis
tiMonth enum value (defined in CChartDateTimeAxis)CChartDateTimeAxis
tiSecond enum value (defined in CChartDateTimeAxis)CChartDateTimeAxis
tiYear enum value (defined in CChartDateTimeAxis)CChartDateTimeAxis
UndoZoom()CChartAxis [protected]
ValueToScreen(double Value) const CChartAxis
ValueToScreenStandard(double Value) const CChartAxis [protected, virtual]
~CChartAxis()CChartAxis [virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_date_time_axis.html b/ChartDemo/Doc/html/class_c_chart_date_time_axis.html new file mode 100644 index 0000000..9349e7c --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_date_time_axis.html @@ -0,0 +1,181 @@ + + +ChartDemo: CChartDateTimeAxis Class Reference + + + + + +
+

CChartDateTimeAxis Class Reference

A specialization of the CChartAxis class for displaying date and time data. +More... +

+#include <ChartDateTimeAxis.h> +

+

+Inheritance diagram for CChartDateTimeAxis:
+
+ +

+ +CChartAxis + +
+ +

+List of all members. + + + + + + + + + + + + + + + +

Public Types

enum  TimeInterval {
+  tiSecond, +tiMinute, +tiHour, +tiDay, +
+  tiMonth, +tiYear +
+ }
 Enum listing the different base intervals.

Public Member Functions

void SetTickIncrement (bool bAuto, TimeInterval Interval, int Multiplier)
 Sets the tick increment.
void SetTickLabelFormat (bool bAutomatic, const TChartString &strFormat)
 Sets the format of the tick labels.
void SetReferenceTick (COleDateTime referenceTick)
 Sets the reference tick.
+


Detailed Description

+A specialization of the CChartAxis class for displaying date and time data.

Member Function Documentation

+ +
+
+ + + + + + + + + +
void CChartDateTimeAxis::SetReferenceTick (COleDateTime  referenceTick  ) 
+
+
+ +

+Sets the reference tick. +

+The reference tick is a date/time which specifies a tick which should always be displayed on the axis. This is needed when the tick interval multiplier is not 1 (e.g. the interval between two ticks is 3 months). In that specific case, there is no way for the control to know which ticks should be displayed (in our example, the chart doesn't know if the first tick will be january, february or march). This is particularly annoying when the axis is panned (in that case, if we always take the first month on the axis as first tick, the ticks will always switch from one month to another). By having a refence tick, this forces the control to calculate all tick intervals based on this reference. It is set to January 1st 2000 by default. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void CChartDateTimeAxis::SetTickIncrement (bool  bAuto,
TimeInterval  Interval,
int  Multiplier 
)
+
+
+ +

+Sets the tick increment. +

+The tick increment is the value between two adjacents ticks on the axis. In case of a date time axis, the interval is specified by a time period because this interval might not be constant (for instance, if a tick interval of one month is specified, the distance between two adjacents ticks is not constant: it depends on the number of days in the month). The full tick interval is made of a base interval (day, month, hour, ...) and a multiplier, that is applied to this base interval. So, for an interval of three months between two ticks, you have to specify tiMonth for the interval and 3 for the multiplier.

Parameters:
+ + + + +
bAuto Specifies if the tick increment is automatically calculated.
Interval The base interval.
Multiplier The multiplier applied to the base interval.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartDateTimeAxis::SetTickLabelFormat (bool  bAutomatic,
const TChartString &  strFormat 
)
+
+
+ +

+Sets the format of the tick labels. +

+

Parameters:
+ + + +
bAutomatic Specifies if the format is calculated automatically.
strFormat The format to apply to the tick label if bAutomatic is false.
+Check the documentation of the COleDateTime::Format function on MSDN for more information about the format string.
+
+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartDateTimeAxis.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartDateTimeAxis.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_date_time_axis.png b/ChartDemo/Doc/html/class_c_chart_date_time_axis.png new file mode 100644 index 0000000000000000000000000000000000000000..b3dc87d04b864a58f564cde30955dcc84be1e7dd GIT binary patch literal 447 zcmeAS@N?(olHy`uVBq!ia0vp^4L}^g!VDyp^%AZFDTx4|5ZC|z{{xx-{~wq?KVbrp z1;z&s9H>6@{|S)GSQ6wH%;50sMjDVE>gnPb64Cm0ig#bL0guCD-|J<0560J^1 zZtwKh^FV7KgR5webn^kTkKOiyFV_cO%6~a&K4S%I!l|VKqVsHTzPmK9xZE4 z%Du1Z8Md#Tp*q3kdd{4g+;bT{_;zOaeCvK|$7o=BUi^8)HOB_CE1MM9=V&kdFsUZ< z=lkgb%RaDdP?LMDBpa+$6XTl<7(^LbtoSz0Qs{WeJ;|5ru$#m@K8MO?H&%yOM((tGCQ)n+Y%Bs( z-t@RE$h*jSHL)Z%yX}2j=Qf6r==};mw!bo9m?RzX*Yq1_LRRd9Dh89oG7;SOn6@nB zRj~44XLjH%u2{65LBeQ->XI3bpY)eKD&rEokQFmdKI;Vst0GWcYz5oCK literal 0 HcmV?d00001 diff --git a/ChartDemo/Doc/html/class_c_chart_drag_line_cursor-members.html b/ChartDemo/Doc/html/class_c_chart_drag_line_cursor-members.html new file mode 100644 index 0000000..4963c6a --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_drag_line_cursor-members.html @@ -0,0 +1,49 @@ + + +ChartDemo: Member List + + + + + +
+

CChartDragLineCursor Member List

This is the complete list of members for CChartDragLineCursor, including all inherited members.

+ + + + + + + + + + + + + + + + + +
CChartCursor(CChartCtrl *pParent)CChartCursor [protected]
CursorMoved(double newXValue, double newYValue)CChartCursor [protected]
Draw(CDC *pDC)CChartDragLineCursor [protected, virtual]
GetCursorId() const CChartCursor [inline]
m_colCursorCChartCursor [protected]
m_lstListenersCChartCursor [protected]
m_pParentCtrlCChartCursor [protected]
m_uCursorIdCChartCursor [protected]
m_uNextFreeIdCChartCursor [protected, static]
OnMouseButtonDown(CPoint mousePoint)CChartDragLineCursor [protected, virtual]
OnMouseButtonUp(CPoint mousePoint)CChartDragLineCursor [protected, virtual]
OnMouseMove(CPoint mousePoint)CChartDragLineCursor [protected, virtual]
RegisterListener(CChartCursorListener *pListener)CChartCursor
SetColor(COLORREF cursorColor)CChartCursor
SetPosition(double dPosition)CChartDragLineCursor
TListenerList typedef (defined in CChartCursor)CChartCursor [protected]
~CChartCursor()CChartCursor [protected, virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_drag_line_cursor.html b/ChartDemo/Doc/html/class_c_chart_drag_line_cursor.html new file mode 100644 index 0000000..02bbaa1 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_drag_line_cursor.html @@ -0,0 +1,78 @@ + + +ChartDemo: CChartDragLineCursor Class Reference + + + + + +
+

CChartDragLineCursor Class Reference

Specialization of a CChartCursor class for a dragline cursor. +More... +

+#include <ChartDragLineCursor.h> +

+

+Inheritance diagram for CChartDragLineCursor:
+
+ +

+ +CChartCursor + +
+ +

+List of all members. + + + + + + + + + + + + + + + + + + +

Public Member Functions

+void SetPosition (double dPosition)
 Sets the position (by value) of the cursor.

Protected Member Functions

+void OnMouseMove (CPoint mousePoint)
 Called when the mouse is moved over the plot area.
+void OnMouseButtonDown (CPoint mousePoint)
 Called when the mouse button is pressed over the plot area.
+void OnMouseButtonUp (CPoint mousePoint)
 Called when the mouse button is released over the plot area.
+void Draw (CDC *pDC)
 Draw the cursor.
+


Detailed Description

+Specialization of a CChartCursor class for a dragline cursor. +

+A dragline cursor is a simple vertical or horizontal line associated with a specific axis. The line can be moved if the user clicks on the line (and keeps the button pressed) and moves the mouse. Once the mouse button is released, the line doesn't move anymore.
+ To create a dragline cursor, call the CreateDragLineCursor from the CChartCtrl class.


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartDragLineCursor.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartDragLineCursor.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_drag_line_cursor.png b/ChartDemo/Doc/html/class_c_chart_drag_line_cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..b7dc7178c1ac0a8c3f016bbc7fffe9c3db1aece2 GIT binary patch literal 480 zcmV<60U!Q}P)IDHeoyQko(}A~}fx4CreRFvR zA$x*EJ5cbsLL1X;9SDM52*6I92@-+G0D*4@)Em%Fp~SIl?zjVSgeasLf$muW1Le~S zQm?$&fvg!=K&n}AhB}bOV(rc|2&e&Z&pn901qT9r0m3FD*k$B;6sr4vY953I1WjqG zBbZkU+TM|rCa0wDNJ^90=&Qnfn!Q=erRmfv=*T*JdO%&5^*8|?y4?5c|D&K$e@9;c W9R;4+*m}AE0000 + +ChartDemo: Member List + + + + + +
+

CChartFont Member List

This is the complete list of members for CChartFont, including all inherited members.

+ + + + + + + + + +
CChartFont(const CChartFont &copy)CChartFont
CChartFont(const TChartString &strFaceName, int iPointSize)CChartFont
CChartFont()CChartFont
operator=(const CChartFont &objectSrc)CChartFont
SelectFont(CDC *pDC) const CChartFont
SetFont(const TChartString &strFaceName, int iPointSize, bool bItalic=false, bool bBold=false, bool bUnderline=false)CChartFont
SetVertical(bool bVertical)CChartFont
UnselectFont(CDC *pDC) const CChartFont
~CChartFont()CChartFont

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_font.html b/ChartDemo/Doc/html/class_c_chart_font.html new file mode 100644 index 0000000..71c2326 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_font.html @@ -0,0 +1,238 @@ + + +ChartDemo: CChartFont Class Reference + + + + + +
+

CChartFont Class Reference

Wrapper class for fonts with advanced properties (italic, bold or underlined). +More... +

+#include <ChartFont.h> +

+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

CChartFont (const CChartFont &copy)
 Copy constructor.
 CChartFont (const TChartString &strFaceName, int iPointSize)
 Constructor.
 CChartFont ()
 Default constructor.
~CChartFont ()
 Destructor.
void SetFont (const TChartString &strFaceName, int iPointSize, bool bItalic=false, bool bBold=false, bool bUnderline=false)
 Sets the font with extended properties.
void SelectFont (CDC *pDC) const
 Select this font in the device context passed in argument.
+void UnselectFont (CDC *pDC) const
 Reset the font to its original in the device context.
void SetVertical (bool bVertical)
 Sets the text in vertical mode.
+void operator= (const CChartFont &objectSrc)
 Assignement operator.
+


Detailed Description

+Wrapper class for fonts with advanced properties (italic, bold or underlined).

Constructor & Destructor Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
CChartFont::CChartFont (const TChartString &  strFaceName,
int  iPointSize 
)
+
+
+ +

+Constructor. +

+

Parameters:
+ + + +
strFaceName The font face name
iPointSize The font point size
+
+ +
+

+ +

+
+ + + + + + + + +
CChartFont::CChartFont (  ) 
+
+
+ +

+Default constructor. +

+Construct a font with the "Microsoft Sans Serif" face name and with a point size of 100. +

+

+


Member Function Documentation

+ +
+
+ + + + + + + + + +
void CChartFont::SelectFont (CDC *  pDC  )  const
+
+
+ +

+Select this font in the device context passed in argument. +

+This function stores the current font selected in the DC to set it back when calling UnselectFont. This function is mainly used internally. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void CChartFont::SetFont (const TChartString &  strFaceName,
int  iPointSize,
bool  bItalic = false,
bool  bBold = false,
bool  bUnderline = false 
)
+
+
+ +

+Sets the font with extended properties. +

+

Parameters:
+ + + + + + +
strFaceName The font face name
iPointSize The font point size
bItalic Specifies if the text is in italic
bBold Specifies if the text is in bold
bUnderline Specifies if the text is underlined
+
+ +
+

+ +

+
+ + + + + + + + + +
void CChartFont::SetVertical (bool  bVertical  ) 
+
+
+ +

+Sets the text in vertical mode. +

+This function is mainly used internally. +

+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartFont.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartFont.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_gantt_serie-members.html b/ChartDemo/Doc/html/class_c_chart_gantt_serie-members.html new file mode 100644 index 0000000..61640aa --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_gantt_serie-members.html @@ -0,0 +1,102 @@ + + +ChartDemo: Member List + + + + + +
+

CChartGanttSerie Member List

This is the complete list of members for CChartGanttSerie, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AddPoint(double StartTime, double EndTime, double YValue)CChartGanttSerie
CChartSerieBase< SChartGanttPoint >::AddPoint(const SChartGanttPoint &newPoint)CChartSerieBase< SChartGanttPoint >
AddPoints(SChartGanttPoint *pPoints, unsigned Count)CChartSerieBase< SChartGanttPoint >
AttachCustomLabel(unsigned uPointIndex, CChartLabel< SChartGanttPoint > *pLabel)CChartSerieBase< SChartGanttPoint >
CChartGanttSerie(CChartCtrl *pParent)CChartGanttSerie
CChartSerie(CChartCtrl *pParent)CChartSerie
CChartSerieBase(CChartCtrl *pParent)CChartSerieBase< SChartGanttPoint >
ClearSerie()CChartSerieBase< SChartGanttPoint >
CreateBalloonLabel(unsigned uPointIndex, const TChartString &strLabelText)CChartSerieBase< SChartGanttPoint >
CreateBalloonLabel(unsigned uPointIndex, CChartLabelProvider< SChartGanttPoint > *pLabelProvider)CChartSerieBase< SChartGanttPoint >
Draw(CDC *pDC)CChartGanttSerie [protected, virtual]
DrawAll(CDC *pDC)CChartGanttSerie [protected, virtual]
DrawLegend(CDC *pDC, const CRect &rectBitmap) const CChartGanttSerie [protected, virtual]
EnableMouseNotifications(bool bClickEnabled, bool bMoveEnabled)CChartSerie
EnableShadow(bool bEnable)CChartSerie
GetBarWidth() const CChartGanttSerie [inline]
GetBorderColor() const CChartGanttSerie [inline]
GetBorderWidth() const CChartGanttSerie [inline]
GetColor() const CChartSerie [inline]
GetName() const CChartSerie [inline]
GetPoint(unsigned index) constCChartSerieBase< SChartGanttPoint >
GetPointsCount() constCChartSerieBase< SChartGanttPoint > [inline, virtual]
GetPointScreenCoord(unsigned uPointIndex)CChartSerieBase< SChartGanttPoint > [virtual]
GetSerieId() const CChartSerie [inline]
GetSerieXMinMax(double &Min, double &Max) constCChartSerieBase< SChartGanttPoint > [virtual]
GetSerieXScreenMinMax(double &Min, double &Max) constCChartSerieBase< SChartGanttPoint > [virtual]
GetSerieYMinMax(double &Min, double &Max) constCChartSerieBase< SChartGanttPoint > [virtual]
GetSerieYScreenMinMax(double &Min, double &Max) constCChartSerieBase< SChartGanttPoint > [virtual]
GetShadowColor() const CChartSerie [inline]
GetVisiblePoints(unsigned &uFirst, unsigned &uLast) constCChartSerieBase< SChartGanttPoint > [protected, virtual]
IsPointOnSerie(const CPoint &screenPoint, unsigned &uIndex) const CChartGanttSerie [virtual]
IsVisible() const CChartSerie [inline]
m_bIsVisibleCChartSerie [protected]
m_bShadowCChartSerie [protected]
m_iShadowDepthCChartSerie [protected]
m_pHorizontalAxisCChartSerie [protected]
m_PlottingRectCChartSerie [protected]
m_pParentCtrlCChartSerie [protected]
m_pVerticalAxisCChartSerie [protected]
m_SerieColorCChartSerie [protected]
m_ShadowColorCChartSerie [protected]
m_strSerieNameCChartSerie [protected]
m_uLastDrawnPointCChartSerieBase< SChartGanttPoint > [protected]
m_vPointsCChartSerieBase< SChartGanttPoint > [protected]
NotifyMouseClickEnabled()CChartSerie [inline, protected]
NotifyMouseMoveEnabled()CChartSerie [inline, protected]
OnMouseEvent(CChartMouseListener::MouseEvent mouseEvent, const CPoint &screenPoint)CChartSerieBase< SChartGanttPoint > [protected, virtual]
RefreshAutoAxes()CChartSerie [protected]
RegisterMouseListener(CChartSeriesMouseListener< SChartGanttPoint > *pListener)CChartSerieBase< SChartGanttPoint >
RemovePointsFromBegin(unsigned Count)CChartSerieBase< SChartGanttPoint >
RemovePointsFromEnd(unsigned Count)CChartSerieBase< SChartGanttPoint >
SetBarWidth(int Width)CChartGanttSerie
SetBorderColor(COLORREF BorderColor)CChartGanttSerie
SetBorderWidth(int Width)CChartGanttSerie
SetColor(COLORREF NewColor)CChartSerie
SetGradient(COLORREF GradientColor, EGradientType GradientType)CChartGanttSerie
SetName(const TChartString &NewName)CChartSerie
SetPoints(SChartGanttPoint *pPoints, unsigned Count)CChartSerieBase< SChartGanttPoint >
SetSeriesOrdering(PointsOrdering newOrdering)CChartSerieBase< SChartGanttPoint > [virtual]
SetShadowColor(COLORREF NewColor)CChartSerie
SetShadowDepth(int Depth)CChartSerie
SetVisible(bool bVisible)CChartSerie
ShowGradient(bool bShow)CChartGanttSerie
UnregisterMouseListener()CChartSerieBase< SChartGanttPoint >
ValueToScreen(double XValue, double YValue, CPoint &ScreenPoint) const CChartSerie
XScreenToValue(long XScreenCoord) const CChartSerie
YScreenToValue(long YScreenCoord) const CChartSerie
~CChartGanttSerie()CChartGanttSerie
~CChartSerie()CChartSerie [virtual]
~CChartSerieBase()CChartSerieBase< SChartGanttPoint > [virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_gantt_serie.html b/ChartDemo/Doc/html/class_c_chart_gantt_serie.html new file mode 100644 index 0000000..ef20bf8 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_gantt_serie.html @@ -0,0 +1,331 @@ + + +ChartDemo: CChartGanttSerie Class Reference + + + + + +
+

CChartGanttSerie Class Reference

Specialization of a CChartSerieBase to display a gantt series. +More... +

+#include <ChartGanttSerie.h> +

+

+Inheritance diagram for CChartGanttSerie:
+
+ +

+ +CChartSerieBase< SChartGanttPoint > +CChartSerie + +
+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

CChartGanttSerie (CChartCtrl *pParent)
 Constructor.
~CChartGanttSerie ()
 Destructor.
void AddPoint (double StartTime, double EndTime, double YValue)
 Adds a new point to the series.
bool IsPointOnSerie (const CPoint &screenPoint, unsigned &uIndex) const
 Tests if a certain screen point is on the series.
+void SetBorderColor (COLORREF BorderColor)
 Sets the bars border color.
+COLORREF GetBorderColor () const
 Returns the bars border color.
+void SetBorderWidth (int Width)
 Sets the bars border width.
+int GetBorderWidth () const
 Returns the bars border width.
+void SetBarWidth (int Width)
 Sets the bars width (in pixels).
+int GetBarWidth () const
 Returns the bars width (in pixels).
+void ShowGradient (bool bShow)
 Specifies if a gradient is applied to the bars.
void SetGradient (COLORREF GradientColor, EGradientType GradientType)
 Sets the gradient style.

Protected Member Functions

void DrawLegend (CDC *pDC, const CRect &rectBitmap) const
 Draws the legend icon for the series.
void Draw (CDC *pDC)
 Draws the most recent points of the series.
void DrawAll (CDC *pDC)
 Redraws the full series.
+


Detailed Description

+Specialization of a CChartSerieBase to display a gantt series. +

+Each point in a gantt series is amde of three values: a start and end time and an Y value. The points are displayed as horizontal bars that are positionned on the Y axis depending on their Y value and which starts at the start time and end at the end time along the X axis.


Member Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void CChartGanttSerie::AddPoint (double  StartTime,
double  EndTime,
double  YValue 
)
+
+
+ +

+Adds a new point to the series. +

+

Parameters:
+ + + + +
StartTime The start time of the Gantt bar
EndTime The end time of the Gantt bar
YValue The YValue of the Gantt bar
+
+ +
+

+ +

+
+ + + + + + + + + +
void CChartGanttSerie::Draw (CDC *  pDC  )  [protected, virtual]
+
+
+ +

+Draws the most recent points of the series. +

+This function should only draw the points that were not previously drawn.

Parameters:
+ + +
pDC The device context used to draw
+
+ +

Implements CChartSerie.

+ +
+

+ +

+
+ + + + + + + + + +
void CChartGanttSerie::DrawAll (CDC *  pDC  )  [protected, virtual]
+
+
+ +

+Redraws the full series. +

+

Parameters:
+ + +
pDC The device context used to draw
+
+ +

Implements CChartSerie.

+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartGanttSerie::DrawLegend (CDC *  pDC,
const CRect &  rectBitmap 
) const [protected, virtual]
+
+
+ +

+Draws the legend icon for the series. +

+

Parameters:
+ + + +
pDC The device context used to draw
rectBitmap The rectangle in which to draw the legend icon
+
+ +

Implements CChartSerie.

+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
bool CChartGanttSerie::IsPointOnSerie (const CPoint &  screenPoint,
unsigned &  uIndex 
) const [virtual]
+
+
+ +

+Tests if a certain screen point is on the series. +

+

Parameters:
+ + + +
screenPoint The screen point to test
uIndex If the point is close to a specific point of the series, its index is stored here.
+
+
Returns:
true if the point is on the series
+ +

Implements CChartSerie.

+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartGanttSerie::SetGradient (COLORREF  GradientColor,
EGradientType  GradientType 
)
+
+
+ +

+Sets the gradient style. +

+

Parameters:
+ + + +
GradientColor The second color used for the gradient (the first one being the original series color).
GradientType The type of gradient used between the two colors (vertical, horizontal, ...)
+
+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartGanttSerie.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartGanttSerie.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_gantt_serie.png b/ChartDemo/Doc/html/class_c_chart_gantt_serie.png new file mode 100644 index 0000000000000000000000000000000000000000..477b41fb1eb76b48003c407d9b8c05bfede2c454 GIT binary patch literal 721 zcmV;?0xtcDP)88PLn8=3NG&W4>E`Tj&l5zQgn9lwofXdi?B2v+IOm+_?u6n8SS+pHfAJHIS z%(w$n^2s1bU|fKWnMTB%QYPwcPvz}|xm|3V{VA~}%^=yIfJxMA=*9mIIn$XZXCCpb z`E-Q;`m+SQu%+utpGo9&7XFAiF&UB_To%w>yBmU<-%Xxw`w`D#qoe<0% z&x*`W$?McQkL=vsti`4(V$8>-letO?StWp4W;2f_MsArMr4!YbF4hBS%0a+%TFpLV zQbRezhOC8bxSnHAn0HGj(Vw<GhR=#XL>kI@6iXbfz<%=}c!j)0r>Gg#FtvuIG7Y3(h + +ChartDemo: Member List + + + + + +
+

CChartGradient Member List

This is the complete list of members for CChartGradient, including all inherited members.

+ + + +
CChartGradient()CChartGradient
DrawGradient(CDC *pDC, const CRect &GradientRect, COLORREF Color1, COLORREF Color2, EGradientType GradientType)CChartGradient [static]
~CChartGradient()CChartGradient

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_gradient.html b/ChartDemo/Doc/html/class_c_chart_gradient.html new file mode 100644 index 0000000..6b76843 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_gradient.html @@ -0,0 +1,118 @@ + + +ChartDemo: CChartGradient Class Reference + + + + + +
+

CChartGradient Class Reference

Helper class to draw gradient. +More... +

+#include <ChartGradient.h> +

+ +

+List of all members. + + + + + + + + + + + + +

Public Member Functions

CChartGradient ()
 Constructor.
~CChartGradient ()
 Destructor.

Static Public Member Functions

static void DrawGradient (CDC *pDC, const CRect &GradientRect, COLORREF Color1, COLORREF Color2, EGradientType GradientType)
 Draws a gradient between two colors inside a rectangle.
+


Detailed Description

+Helper class to draw gradient. +

+It only contains a static function to draw the gradient. This is mainly used internally.


Member Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void CChartGradient::DrawGradient (CDC *  pDC,
const CRect &  GradientRect,
COLORREF  Color1,
COLORREF  Color2,
EGradientType  GradientType 
) [static]
+
+
+ +

+Draws a gradient between two colors inside a rectangle. +

+

Parameters:
+ + + + + + +
pDC The device context with which to draw.
GradientRect The rectangle in which to draw the gradient
Color1 The first gradient color
Color2 The second gradient color
GradientType The type of gradient to use in the rectangle
+
+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartGradient.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartGradient.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_grid-members.html b/ChartDemo/Doc/html/class_c_chart_grid-members.html new file mode 100644 index 0000000..a334629 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_grid-members.html @@ -0,0 +1,36 @@ + + +ChartDemo: Member List + + + + + +
+

CChartGrid Member List

This is the complete list of members for CChartGrid, including all inherited members.

+ + + + +
GetColor() const CChartGrid [inline]
IsVisible() const CChartGrid [inline]
SetColor(COLORREF NewColor)CChartGrid
SetVisible(bool bVisible)CChartGrid

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_grid.html b/ChartDemo/Doc/html/class_c_chart_grid.html new file mode 100644 index 0000000..0fc7f0b --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_grid.html @@ -0,0 +1,63 @@ + + +ChartDemo: CChartGrid Class Reference + + + + + +
+

CChartGrid Class Reference

Class which draws the grid associated with a specific axis. +More... +

+#include <ChartGrid.h> +

+ +

+List of all members. + + + + + + + + + + + + + + +

Public Member Functions

+void SetVisible (bool bVisible)
 Shows/hides the grid.
+bool IsVisible () const
 Returns true if the grid is visible.
+void SetColor (COLORREF NewColor)
 Sets the color of the grid.
+COLORREF GetColor () const
 Returns the grid color.
+


Detailed Description

+Class which draws the grid associated with a specific axis. +

+This object is retrieved through the CChartAxis::GetGrid function.


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartGrid.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartGrid.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_label-members.html b/ChartDemo/Doc/html/class_c_chart_label-members.html new file mode 100644 index 0000000..bdd2f80 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_label-members.html @@ -0,0 +1,46 @@ + + +ChartDemo: Member List + + + + + +
+

CChartLabel< PointType > Member List

This is the complete list of members for CChartLabel< PointType >, including all inherited members.

+ + + + + + + + + + + + + + +
CChartLabel(CChartCtrl *pParentCtrl, CChartSerieBase< PointType > *pParentSeries)CChartLabel< PointType > [protected]
Draw(CDC *pDC, unsigned uPointIndex)=0CChartLabel< PointType > [protected, pure virtual]
m_bIsVisibleCChartLabel< PointType > [protected]
m_iFontSizeCChartLabel< PointType > [protected]
m_pLabelProviderCChartLabel< PointType > [protected]
m_pParentCtrlCChartLabel< PointType > [protected]
m_pParentSeriesCChartLabel< PointType > [protected]
m_strFontNameCChartLabel< PointType > [protected]
m_strLabelTextCChartLabel< PointType > [protected]
SetFont(int nPointSize, const TChartString &strFaceName)CChartLabel< PointType >
SetLabelProvider(CChartLabelProvider< PointType > *pProvider)CChartLabel< PointType > [inline]
SetLabelText(const TChartString &strText)CChartLabel< PointType >
SetVisisble(bool bVisible)CChartLabel< PointType >
~CChartLabel()CChartLabel< PointType > [protected, virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_label.html b/ChartDemo/Doc/html/class_c_chart_label.html new file mode 100644 index 0000000..69792ff --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_label.html @@ -0,0 +1,183 @@ + + +ChartDemo: CChartLabel< PointType > Class Template Reference + + + + + +
+

CChartLabel< PointType > Class Template Reference

Draws a label containing some text which is attached to a point of a series. +More... +

+#include <ChartLabel.h> +

+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

+void SetLabelText (const TChartString &strText)
 Sets a static text to be displayed in the label.
void SetFont (int nPointSize, const TChartString &strFaceName)
 Sets the font of the text label.
+void SetVisisble (bool bVisible)
 Shows/hides the label.
+void SetLabelProvider (CChartLabelProvider< PointType > *pProvider)
 Sets a label provider for more flexibility in how the text is supplied.

Protected Member Functions

CChartLabel (CChartCtrl *pParentCtrl, CChartSerieBase< PointType > *pParentSeries)
 Constructor.
+virtual ~CChartLabel ()
 Destructor.
virtual void Draw (CDC *pDC, unsigned uPointIndex)=0
 Draws the label.

Protected Attributes

+bool m_bIsVisible
 Specifies if the label is visible or not.
+int m_iFontSize
 The text font size.
+TChartString m_strFontName
 The text font face name.
+TChartString m_strLabelText
 The static text of the label.
+CChartLabelProvider< PointType > * m_pLabelProvider
 The text provider.
+CChartCtrlm_pParentCtrl
 The parent charting control.
+CChartSerieBase< PointType > * m_pParentSeries
 The parent series.
+


Detailed Description

+

template<class PointType>
+ class CChartLabel< PointType >

+ +Draws a label containing some text which is attached to a point of a series. +

+This is a base class which should be overriden for specific label types.


Member Function Documentation

+ +
+
+
+template<class PointType>
+ + + + + + + + + + + + + + + + + + +
virtual void CChartLabel< PointType >::Draw (CDC *  pDC,
unsigned  uPointIndex 
) [protected, pure virtual]
+
+
+ +

+Draws the label. +

+This pure virtual function must be overriden by all child classes. +

Implemented in CChartBalloonLabel< PointType >.

+ +
+

+ +

+
+
+template<class PointType>
+ + + + + + + + + + + + + + + + + + +
void CChartLabel< PointType >::SetFont (int  nPointSize,
const TChartString &  strFaceName 
)
+
+
+ +

+Sets the font of the text label. +

+

Parameters:
+ + + +
nPointSize The font point size
strFaceName The font face name
+
+ +

Reimplemented in CChartBalloonLabel< PointType >.

+ +
+

+


The documentation for this class was generated from the following file: +
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_label.png b/ChartDemo/Doc/html/class_c_chart_label.png new file mode 100644 index 0000000000000000000000000000000000000000..ab89b669065ec4b3333d171338ab37bc99657bef GIT binary patch literal 414 zcmV;P0b%}$P)8k!2crcAnsoPyN-+nb!UV%Y+_BdF-+faFtI-D^LIZ zsq{av|0UlvfA#*M-z(wuD}&p#|D!hePv?98-#d2elGn{&rgQmex}D0Oz5l@ve(-}I z{I~MIukG*k_0|2v9vi&!fh9)f80NeLgyvM$VRaZU@WVr`y3)$0SgS+8lh9X~6AxM7 zHKU&CLzK%lcvOpW)?Y%oSz+nwK(59j$rYrR4dU*F5f%8h*k{ocXZT ze~vcy-^MTIuin4v*Go?Gvq-gnTMF)%`|q&9e>%VO|K73d9j)x? + +ChartDemo: Member List + + + + + +
+

CChartLabelProvider< PointType > Member List

This is the complete list of members for CChartLabelProvider< PointType >, including all inherited members.

+ + + +
CChartLabelProvider()CChartLabelProvider< PointType > [inline]
GetText(CChartSerieBase< PointType > *pSerie, unsigned PointIndex)=0CChartLabelProvider< PointType > [pure virtual]
~CChartLabelProvider()CChartLabelProvider< PointType > [inline, virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_label_provider.html b/ChartDemo/Doc/html/class_c_chart_label_provider.html new file mode 100644 index 0000000..3555863 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_label_provider.html @@ -0,0 +1,103 @@ + + +ChartDemo: CChartLabelProvider< PointType > Class Template Reference + + + + + +
+

CChartLabelProvider< PointType > Class Template Reference

Interface which should be implemented in order to provide text to a label. +More... +

+#include <ChartLabel.h> +

+ +

+List of all members. + + + + + + + + + + + +

Public Member Functions

CChartLabelProvider ()
 Constructor.
+virtual ~CChartLabelProvider ()
 Destructor.
virtual TChartString GetText (CChartSerieBase< PointType > *pSerie, unsigned PointIndex)=0
 Method to override in order to provide the text of the label.
+


Detailed Description

+

template<class PointType>
+ class CChartLabelProvider< PointType >

+ +Interface which should be implemented in order to provide text to a label. +

+This class is a template class with the template parameter being the point type of the series to which the label is attached.

+Using a CChartLabelProvider provides more flexibility in the way to supply text to the label. You can for instance embedd in the string some information about the point (XValue, YValue, index, ...). In that case, a single CChartLabelProvider object can be provided for all labels. Changing the displayed text of all labels becomes also easier: you only have to adapt the string returned by this object and refresh the control and all labels will be updated.


Member Function Documentation

+ +
+
+
+template<class PointType>
+ + + + + + + + + + + + + + + + + + +
virtual TChartString CChartLabelProvider< PointType >::GetText (CChartSerieBase< PointType > *  pSerie,
unsigned  PointIndex 
) [pure virtual]
+
+
+ +

+Method to override in order to provide the text of the label. +

+

Parameters:
+ + + +
pSerie The series to which the label is attached
uPtIndex The index of the point in the series to which the label is attached
+
+
Returns:
a string which will be the text displayed in the label.
+ +
+

+


The documentation for this class was generated from the following file: +
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_legend-members.html b/ChartDemo/Doc/html/class_c_chart_legend-members.html new file mode 100644 index 0000000..066c37b --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_legend-members.html @@ -0,0 +1,51 @@ + + +ChartDemo: Member List + + + + + +
+

CChartLegend Member List

This is the complete list of members for CChartLegend, including all inherited members.

+ + + + + + + + + + + + + + + + + + + +
DockLegend(DockSide dsSide)CChartLegend
DockSide enum nameCChartLegend
dsDockBottom enum value (defined in CChartLegend)CChartLegend
dsDockLeft enum value (defined in CChartLegend)CChartLegend
dsDockRight enum value (defined in CChartLegend)CChartLegend
dsDockTop enum value (defined in CChartLegend)CChartLegend
EnableShadow(bool bEnable)CChartLegend
GetBackColor() const CChartLegend [inline]
GetShadowColor() const CChartLegend [inline]
IsPointInside(const CPoint &screenPoint) const CChartLegend
IsVisible() const CChartLegend [inline]
SetBackColor(COLORREF NewColor)CChartLegend
SetFont(int iPointSize, const TChartString &strFaceName)CChartLegend
SetHorizontalMode(bool bHorizontal)CChartLegend
SetShadowColor(COLORREF NewColor)CChartLegend
SetShadowDepth(int Depth)CChartLegend
SetTransparent(bool bTransparent)CChartLegend
SetVisible(bool bVisible)CChartLegend
UndockLegend(int iLeftPos, int iTopPos)CChartLegend

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_legend.html b/ChartDemo/Doc/html/class_c_chart_legend.html new file mode 100644 index 0000000..23ece9c --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_legend.html @@ -0,0 +1,169 @@ + + +ChartDemo: CChartLegend Class Reference + + + + + +
+

CChartLegend Class Reference

This class is responsible for the legend displayed on the control. +More... +

+#include <ChartLegend.h> +

+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Types

enum  DockSide { dsDockRight, +dsDockLeft, +dsDockTop, +dsDockBottom + }
 Enumeration specifying on which side of the control the legend is docked.

Public Member Functions

+void SetFont (int iPointSize, const TChartString &strFaceName)
 Sets the font used to display the series names.
+void DockLegend (DockSide dsSide)
 Dock the legend on a specific side of the control. Default is right.
void UndockLegend (int iLeftPos, int iTopPos)
 Undock the legend.
+void SetTransparent (bool bTransparent)
 Sets the background of the legend transparent.
void SetHorizontalMode (bool bHorizontal)
 Sets the legend in horizontal/vertical mode.
+void SetVisible (bool bVisible)
 Sets the legend visible/invisible.
+bool IsVisible () const
 Returns true if the legend is visible.
+COLORREF GetBackColor () const
 Returns the back color of the legend.
+void SetBackColor (COLORREF NewColor)
 Sets the back color of the legend.
+COLORREF GetShadowColor () const
 Returns the shadow color.
+void SetShadowColor (COLORREF NewColor)
 Sets the shadow color.
+void EnableShadow (bool bEnable)
 Enables/disables the shadow.
+void SetShadowDepth (int Depth)
 Sets the shadow depth (in pixels).
+BOOL IsPointInside (const CPoint &screenPoint) const
 Returns true if the screen point is on the legend region.
+


Detailed Description

+This class is responsible for the legend displayed on the control. +

+Series which are named will be displayed in the legend. The legend object is retrieved by calling the GetLegend() function on the CChartCtrl class.


Member Function Documentation

+ +
+
+ + + + + + + + + +
void CChartLegend::SetHorizontalMode (bool  bHorizontal  ) 
+
+
+ +

+Sets the legend in horizontal/vertical mode. +

+In horizontal mode, the names are drawn next to each other instead of on top of each other. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartLegend::UndockLegend (int  iLeftPos,
int  iTopPos 
)
+
+
+ +

+Undock the legend. +

+When the legend is undocked (floating), it doesn't take any margin size but is drawn on top of the control at the specified location (it can be above the plotting area for instance).

Parameters:
+ + + +
iLeftPos The left position of the legend, in pixels (from the left of the control)
iTopPos The top position of the legend, in pixels (from the top of the control)
+
+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartLegend.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartLegend.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_line_serie-members.html b/ChartDemo/Doc/html/class_c_chart_line_serie-members.html new file mode 100644 index 0000000..03016a5 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_line_serie-members.html @@ -0,0 +1,107 @@ + + +ChartDemo: Member List + + + + + +
+

CChartLineSerie Member List

This is the complete list of members for CChartLineSerie, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AddPoint(double X, double Y)CChartXYSerie
CChartSerieBase< SChartXYPoint >::AddPoint(const SChartXYPoint &newPoint)CChartSerieBase< SChartXYPoint >
AddPoints(double *pX, double *pY, unsigned Count)CChartXYSerie
CChartSerieBase< SChartXYPoint >::AddPoints(SChartXYPoint *pPoints, unsigned Count)CChartSerieBase< SChartXYPoint >
AttachCustomLabel(unsigned uPointIndex, CChartLabel< SChartXYPoint > *pLabel)CChartSerieBase< SChartXYPoint >
CChartLineSerie(CChartCtrl *pParent)CChartLineSerie
CChartSerie(CChartCtrl *pParent)CChartSerie
CChartSerieBase(CChartCtrl *pParent)CChartSerieBase< SChartXYPoint >
CChartXYSerie(CChartCtrl *pParent)CChartXYSerie
ClearSerie()CChartSerieBase< SChartXYPoint >
CreateBalloonLabel(unsigned uPointIndex, const TChartString &strLabelText)CChartSerieBase< SChartXYPoint >
CreateBalloonLabel(unsigned uPointIndex, CChartLabelProvider< SChartXYPoint > *pLabelProvider)CChartSerieBase< SChartXYPoint >
EnableMouseNotifications(bool bClickEnabled, bool bMoveEnabled)CChartSerie
EnableShadow(bool bEnable)CChartSerie
GetBezierControlPoints(unsigned uFirst, unsigned uLast, SChartXYPoint *&pKnots, SChartXYPoint *&pFirstControlPoints, SChartXYPoint *&pSecondControlPoints) const CChartXYSerie [protected]
GetColor() const CChartSerie [inline]
GetName() const CChartSerie [inline]
GetPenStyle() const CChartLineSerie [inline]
GetPoint(unsigned index) constCChartSerieBase< SChartXYPoint >
GetPointsCount() constCChartSerieBase< SChartXYPoint > [inline, virtual]
GetPointScreenCoord(unsigned uPointIndex)CChartSerieBase< SChartXYPoint > [virtual]
GetSerieId() const CChartSerie [inline]
GetSerieXMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetSerieXScreenMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetSerieYMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetSerieYScreenMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetShadowColor() const CChartSerie [inline]
GetUserData(unsigned uPointIndex)CChartXYSerie
GetVisiblePoints(unsigned &uFirst, unsigned &uLast) constCChartSerieBase< SChartXYPoint > [protected, virtual]
GetWidth() const CChartLineSerie [inline]
GetXPointValue(unsigned PointIndex) const CChartXYSerie
GetYPointValue(unsigned PointIndex) const CChartXYSerie
IsPointOnSerie(const CPoint &screenPoint, unsigned &uIndex) const CChartLineSerie [virtual]
IsVisible() const CChartSerie [inline]
m_bIsVisibleCChartSerie [protected]
m_bShadowCChartSerie [protected]
m_iShadowDepthCChartSerie [protected]
m_pHorizontalAxisCChartSerie [protected]
m_PlottingRectCChartSerie [protected]
m_pParentCtrlCChartSerie [protected]
m_pVerticalAxisCChartSerie [protected]
m_SerieColorCChartSerie [protected]
m_ShadowColorCChartSerie [protected]
m_strSerieNameCChartSerie [protected]
m_uLastDrawnPointCChartSerieBase< SChartXYPoint > [protected]
m_vPointsCChartSerieBase< SChartXYPoint > [protected]
NotifyMouseClickEnabled()CChartSerie [inline, protected]
NotifyMouseMoveEnabled()CChartSerie [inline, protected]
OnMouseEvent(CChartMouseListener::MouseEvent mouseEvent, const CPoint &screenPoint)CChartSerieBase< SChartXYPoint > [protected, virtual]
RefreshAutoAxes()CChartSerie [protected]
RegisterMouseListener(CChartSeriesMouseListener< SChartXYPoint > *pListener)CChartSerieBase< SChartXYPoint >
RemovePointsFromBegin(unsigned Count)CChartSerieBase< SChartXYPoint >
RemovePointsFromEnd(unsigned Count)CChartSerieBase< SChartXYPoint >
SetColor(COLORREF NewColor)CChartSerie
SetName(const TChartString &NewName)CChartSerie
SetPenStyle(int NewStyle)CChartLineSerie
SetPoints(double *pX, double *pY, unsigned Count)CChartXYSerie
CChartSerieBase< SChartXYPoint >::SetPoints(SChartXYPoint *pPoints, unsigned Count)CChartSerieBase< SChartXYPoint >
SetSeriesOrdering(PointsOrdering newOrdering)CChartSerieBase< SChartXYPoint > [virtual]
SetShadowColor(COLORREF NewColor)CChartSerie
SetShadowDepth(int Depth)CChartSerie
SetSmooth(bool bSmooth)CChartLineSerie
SetUserData(unsigned uPointIndex, void *pData)CChartXYSerie
SetVisible(bool bVisible)CChartSerie
SetWidth(int PenWidth)CChartLineSerie
SetXPointValue(unsigned PointIndex, double NewVal)CChartXYSerie
SetYPointValue(unsigned PointIndex, double NewVal)CChartXYSerie
UnregisterMouseListener()CChartSerieBase< SChartXYPoint >
ValueToScreen(double XValue, double YValue, CPoint &ScreenPoint) const CChartSerie
XScreenToValue(long XScreenCoord) const CChartSerie
YScreenToValue(long YScreenCoord) const CChartSerie
~CChartLineSerie()CChartLineSerie [virtual]
~CChartSerie()CChartSerie [virtual]
~CChartSerieBase()CChartSerieBase< SChartXYPoint > [virtual]
~CChartXYSerie()CChartXYSerie [virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_line_serie.html b/ChartDemo/Doc/html/class_c_chart_line_serie.html new file mode 100644 index 0000000..f131797 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_line_serie.html @@ -0,0 +1,171 @@ + + +ChartDemo: CChartLineSerie Class Reference + + + + + +
+

CChartLineSerie Class Reference

Specialization of a CChartSerie to display a line series. +More... +

+#include <ChartLineSerie.h> +

+

+Inheritance diagram for CChartLineSerie:
+
+ +

+ +CChartXYSerie +CChartSerieBase< SChartXYPoint > +CChartSerie + +
+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

int GetPenStyle () const
 Returns the pen style (plain, dashed, dotted, ...).
void SetPenStyle (int NewStyle)
 Sets the pen style (plain, dashed, dotted, ...).
+int GetWidth () const
 Returns the pen width.
+void SetWidth (int PenWidth)
 Sets the pen width.
+void SetSmooth (bool bSmooth)
 Enables the smoothing of the curve (slower).
CChartLineSerie (CChartCtrl *pParent)
 Constructor.
+virtual ~CChartLineSerie ()
 Destructor.
bool IsPointOnSerie (const CPoint &screenPoint, unsigned &uIndex) const
 Check whether a screen point is on the series.
+


Detailed Description

+Specialization of a CChartSerie to display a line series. +

+The data points are connected by line segments. The curve can also be smoothed.


Member Function Documentation

+ +
+
+ + + + + + + + +
int CChartLineSerie::GetPenStyle (  )  const [inline]
+
+
+ +

+Returns the pen style (plain, dashed, dotted, ...). +

+For a list of pen styles available, see the CreatePen function in MSDN. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
bool CChartLineSerie::IsPointOnSerie (const CPoint &  screenPoint,
unsigned &  uIndex 
) const [virtual]
+
+
+ +

+Check whether a screen point is on the series. +

+This function returns true if the screen point is close to a line segment. If the screen point is also close to a specific point of the series, the index of the point is stored in the uIndex parameter. Otherwise, this parameter contains INVALID_POINT.

Parameters:
+ + + +
screenPoint The screen point to test
uIndex If the point is close to a specific point of the series, its index is stored here.
+
+
Returns:
true if the point is on the series
+ +

Implements CChartSerie.

+ +
+

+ +

+
+ + + + + + + + + +
void CChartLineSerie::SetPenStyle (int  NewStyle  ) 
+
+
+ +

+Sets the pen style (plain, dashed, dotted, ...). +

+For a list of pen styles available, see the CreatePen function in MSDN. +

+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartLineSerie.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartLineSerie.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_line_serie.png b/ChartDemo/Doc/html/class_c_chart_line_serie.png new file mode 100644 index 0000000000000000000000000000000000000000..af2aa05eada4c1f770d537206984e7abb090dee4 GIT binary patch literal 824 zcmV-81IPS{P)|SV}a{nVNNPtN~{Lx}h!u;tp4H)w?Snf2a)88x0_w>hKSip_X z39__$*{3(RrLB_c+Tegd(yj0wFmY|h15ZeQnnzJu$le%Ng?Z^`7(6P$P&aC8-IBna8 znM%G0_UXKEaM>4s;9h14%09H@J$>)3i~i)?)iW=go=0heoEzNBEP>rSyEk?%=A={E zFUuGg$?LsiU#>NI&s;l8ASrqzzH$j0E?nxWv$Kox_ndmqTsupU7c&J0fY_h5{Ol~j?C)0V?7qe + +ChartDemo: Member List + + + + + +
+

CChartLogarithmicAxis Member List

This is the complete list of members for CChartLogarithmicAxis, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CChartAxis()CChartAxis
EAxisAutoModes enum nameCChartAxis
EnableScrollBar(bool bEnabled)CChartAxis
FullAutomatic enum valueCChartAxis
GetAutoHideScrollBar() const CChartAxis
GetAutomaticMode() const CChartAxis [inline]
GetAxisLenght() const CChartAxis [protected]
GetGrid() const CChartAxis [inline]
GetLabel() const CChartAxis [inline]
GetMinMax(double &Minimum, double &Maximum) const CChartAxis [inline]
GetPosition()CChartAxis
GetSeriesMinMax(double &Minimum, double &Maximum)CChartAxis [protected]
GetSeriesScreenMinMax(double &Minimum, double &Maximum)CChartAxis [protected]
GetTextColor() const CChartAxis [inline]
IsAutomatic() const CChartAxis [inline]
IsHorizontal() const CChartAxis [inline]
IsInverted() const CChartAxis [inline]
IsPointInside(const CPoint &screenPoint) const CChartAxis
IsVisible() const CChartAxis [inline]
m_AutoModeCChartAxis [protected]
m_AxisRectCChartAxis [protected]
m_bAutoTicksCChartAxis [protected]
m_bDiscreteCChartAxis [protected]
m_bIsHorizontalCChartAxis [protected]
m_bIsInvertedCChartAxis [protected]
m_bIsSecondaryCChartAxis [protected]
m_bIsVisibleCChartAxis [protected]
m_EndPosCChartAxis [protected]
m_MaxValueCChartAxis [protected]
m_MinValueCChartAxis [protected]
m_pParentCtrlCChartAxis [protected]
m_StartPosCChartAxis [protected]
m_UnzoomMaxCChartAxis [protected]
m_UnzoomMinCChartAxis [protected]
NotAutomatic enum valueCChartAxis
ScreenAutomatic enum valueCChartAxis
ScrollBarEnabled() const CChartAxis [inline]
SetAutoHideScrollBar(bool bAutoHide)CChartAxis
SetAutomatic(bool bAutomatic)CChartAxis
SetAutomaticMode(EAxisAutoModes AutoMode)CChartAxis
SetAxisColor(COLORREF NewColor)CChartAxis
SetDiscrete(bool bDiscrete)CChartAxis [virtual]
SetFont(int nPointSize, const TChartString &strFaceName)CChartAxis
SetInverted(bool bInverted)CChartAxis
SetMarginSize(bool bAuto, int iNewSize)CChartAxis
SetMinMax(double Minimum, double Maximum)CChartAxis
SetPanZoomEnabled(bool bEnabled)CChartAxis [inline]
SetTextColor(COLORREF NewColor)CChartAxis
SetVisible(bool bVisible)CChartAxis
SetZoomLimit(double dLimit)CChartAxis [inline]
SetZoomMinMax(double Minimum, double Maximum)CChartAxis [protected, virtual]
UndoZoom()CChartAxis [protected]
ValueToScreen(double Value) const CChartAxis
~CChartAxis()CChartAxis [virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_logarithmic_axis.html b/ChartDemo/Doc/html/class_c_chart_logarithmic_axis.html new file mode 100644 index 0000000..675a2a8 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_logarithmic_axis.html @@ -0,0 +1,55 @@ + + +ChartDemo: CChartLogarithmicAxis Class Reference + + + + + +
+

CChartLogarithmicAxis Class Reference

Specialization of a CChartAxis to display a logarithmic scale. +More... +

+#include <ChartLogarithmicAxis.h> +

+

+Inheritance diagram for CChartLogarithmicAxis:
+
+ +

+ +CChartAxis + +
+ +

+List of all members. + +
+


Detailed Description

+Specialization of a CChartAxis to display a logarithmic scale. +

+Currently this class only allows to have a logarithmic axis with a base of 10.


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartLogarithmicAxis.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartLogarithmicAxis.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_logarithmic_axis.png b/ChartDemo/Doc/html/class_c_chart_logarithmic_axis.png new file mode 100644 index 0000000000000000000000000000000000000000..d7c9698f3edb206fcdb668d096bb6d7b2ba2cec6 GIT binary patch literal 468 zcmeAS@N?(olHy`uVBq!ia0vp^y+9nm!VDy@U3i@iq$C1-LR|m<{|{vT|9@cq{DcWW z78oBmaG?6o|0h5$V@Z%-FoVOh8)-mxmZytjNJQ(~sos5u6?od-o?Vlh$Dl5;Rs5CK zcl$#()NF(nO>aFu0znB;8Cu2Figf(8I zRb^Flcxjw;-`mffe^H8jc|I*Q?I0e)>W2_>&25i*L?<^=}1NZ=$dD z{BW0mXAXb%WtPX~uifk6{;jjQ*`n;RTY*(>kzFC%-|~M9UlVv&+`0cy4HyLsp00i_ I>zopr0Eg4j4*&oF literal 0 HcmV?d00001 diff --git a/ChartDemo/Doc/html/class_c_chart_mouse_listener-members.html b/ChartDemo/Doc/html/class_c_chart_mouse_listener-members.html new file mode 100644 index 0000000..3a5673c --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_mouse_listener-members.html @@ -0,0 +1,46 @@ + + +ChartDemo: Member List + + + + + +
+

CChartMouseListener Member List

This is the complete list of members for CChartMouseListener, including all inherited members.

+ + + + + + + + + + + + + + +
CChartMouseListener()CChartMouseListener [inline]
LButtonDoubleClick enum value (defined in CChartMouseListener)CChartMouseListener
LButtonDown enum value (defined in CChartMouseListener)CChartMouseListener
LButtonUp enum value (defined in CChartMouseListener)CChartMouseListener
MouseEvent enum nameCChartMouseListener
MouseMove enum value (defined in CChartMouseListener)CChartMouseListener
OnMouseEventAxis(MouseEvent mouseEvent, CPoint point, CChartAxis *pAxisClicked)CChartMouseListener [inline, virtual]
OnMouseEventLegend(MouseEvent mouseEvent, CPoint point)CChartMouseListener [inline, virtual]
OnMouseEventPlotArea(MouseEvent mouseEvent, CPoint point)CChartMouseListener [inline, virtual]
OnMouseEventTitle(MouseEvent mouseEvent, CPoint point)CChartMouseListener [inline, virtual]
RButtonDoubleClick enum value (defined in CChartMouseListener)CChartMouseListener
RButtonDown enum value (defined in CChartMouseListener)CChartMouseListener
RButtonUp enum value (defined in CChartMouseListener)CChartMouseListener
~CChartMouseListener()CChartMouseListener [inline, virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_mouse_listener.html b/ChartDemo/Doc/html/class_c_chart_mouse_listener.html new file mode 100644 index 0000000..10e243f --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_mouse_listener.html @@ -0,0 +1,237 @@ + + +ChartDemo: CChartMouseListener Class Reference + + + + + +
+

CChartMouseListener Class Reference

Listener for mouse events occuring on the chart control. +More... +

+#include <ChartMouseListener.h> +

+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + +

Public Types

enum  MouseEvent {
+  MouseMove, +LButtonUp, +LButtonDown, +LButtonDoubleClick, +
+  RButtonUp, +RButtonDown, +RButtonDoubleClick +
+ }
 Enumeration listing the type of mouse events.

Public Member Functions

CChartMouseListener ()
 Constructor.
+virtual ~CChartMouseListener ()
 Destructor.
virtual void OnMouseEventTitle (MouseEvent mouseEvent, CPoint point)
 Virtual function to implement in order to be notified when the title is clicked.
virtual void OnMouseEventAxis (MouseEvent mouseEvent, CPoint point, CChartAxis *pAxisClicked)
 Virtual function to implement in order to be notified when an axis is clicked.
virtual void OnMouseEventLegend (MouseEvent mouseEvent, CPoint point)
 Virtual function to implement in order to be notified when the legend is clicked.
virtual void OnMouseEventPlotArea (MouseEvent mouseEvent, CPoint point)
 Virtual function to implement in order to be notified when the plotting area is clicked.
+


Detailed Description

+Listener for mouse events occuring on the chart control. +

+This is an interface which must be implemented in order to receive mouse notifications. You can then register your class with the chart control by calling RegisterMouseListener.


Member Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual void CChartMouseListener::OnMouseEventAxis (MouseEvent  mouseEvent,
CPoint  point,
CChartAxis pAxisClicked 
) [inline, virtual]
+
+
+ +

+Virtual function to implement in order to be notified when an axis is clicked. +

+

Parameters:
+ + + + +
mouseEvent The mouse event which occured
point The screen point on which the event occured
pAxisClicked The axis on which the event occured
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
virtual void CChartMouseListener::OnMouseEventLegend (MouseEvent  mouseEvent,
CPoint  point 
) [inline, virtual]
+
+
+ +

+Virtual function to implement in order to be notified when the legend is clicked. +

+

Parameters:
+ + + +
mouseEvent The mouse event which occured
point The screen point on which the event occured
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
virtual void CChartMouseListener::OnMouseEventPlotArea (MouseEvent  mouseEvent,
CPoint  point 
) [inline, virtual]
+
+
+ +

+Virtual function to implement in order to be notified when the plotting area is clicked. +

+

Parameters:
+ + + +
mouseEvent The mouse event which occured
point The screen point on which the event occured
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
virtual void CChartMouseListener::OnMouseEventTitle (MouseEvent  mouseEvent,
CPoint  point 
) [inline, virtual]
+
+
+ +

+Virtual function to implement in order to be notified when the title is clicked. +

+

Parameters:
+ + + +
mouseEvent The mouse event which occured
point The screen point on which the event occured
+
+ +
+

+


The documentation for this class was generated from the following file: +
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_points_array-members.html b/ChartDemo/Doc/html/class_c_chart_points_array-members.html new file mode 100644 index 0000000..1c6d7b7 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_points_array-members.html @@ -0,0 +1,51 @@ + + +ChartDemo: Member List + + + + + +
+

CChartPointsArray< T > Member List

This is the complete list of members for CChartPointsArray< T >, including all inherited members.

+ + + + + + + + + + + + + + + + + + + +
AddPoint(const T &newPoint)CChartPointsArray< T > [inline]
AddPoints(T *pPoints, unsigned uCount)CChartPointsArray< T > [inline]
CChartPointsArray(unsigned iResize=1000)CChartPointsArray< T > [inline]
Clear()CChartPointsArray< T > [inline]
GetInternalBuffer() const CChartPointsArray< T > [inline]
GetOrdering() const CChartPointsArray< T > [inline]
GetPointsCount() const CChartPointsArray< T > [inline]
GetSerieXMinMax(double &Min, double &Max) const CChartPointsArray< T > [inline]
GetSerieYMinMax(double &Min, double &Max) const CChartPointsArray< T > [inline]
GetVisiblePoints(double dAxisMin, double dAxisMax, unsigned &uFirstPt, unsigned &uLastPt) const CChartPointsArray< T > [inline]
operator[](unsigned Index)CChartPointsArray< T > [inline]
operator[](unsigned Index) const CChartPointsArray< T > [inline]
RemovePointsFromBegin(unsigned Count)CChartPointsArray< T > [inline]
RemovePointsFromEnd(unsigned Count)CChartPointsArray< T > [inline]
ReorderPoints()CChartPointsArray< T > [inline]
SetOrdering(PointsOrdering newOrdering)CChartPointsArray< T > [inline]
SetPoints(T *pPoints, unsigned uCount)CChartPointsArray< T > [inline]
SetResize(int iResize)CChartPointsArray< T > [inline]
~CChartPointsArray()CChartPointsArray< T > [inline]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_points_array.html b/ChartDemo/Doc/html/class_c_chart_points_array.html new file mode 100644 index 0000000..b099b72 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_points_array.html @@ -0,0 +1,351 @@ + + +ChartDemo: CChartPointsArray< T > Class Template Reference + + + + + +
+

CChartPointsArray< T > Class Template Reference

Manages an array of points which supports fast resizing. +More... +

+#include <ChartPointsArray.h> +

+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

 CChartPointsArray (unsigned iResize=1000)
 Constructor.
~CChartPointsArray ()
 Destructor.
+unsigned GetPointsCount () const
 Returns the number of points currently stored.
+void SetResize (int iResize)
 Sets the size by which the internal buffer is increased when reallocation occurs.
void AddPoint (const T &newPoint)
 Adds a new point in the array.
void AddPoints (T *pPoints, unsigned uCount)
 Adds multiple points in the array.
void SetPoints (T *pPoints, unsigned uCount)
 Sets multiple points in the array.
+void Clear ()
 Removes all the points from the array.
+void RemovePointsFromBegin (unsigned Count)
 Removes a certain amount of points from the begining of the series.
+void RemovePointsFromEnd (unsigned Count)
 Removes a certain amount of points from the end of the series.
+T & operator[] (unsigned Index)
 Retrieves the points at the specified index.
+const T & operator[] (unsigned Index) const
 Retrieves the points at the specified index.
+bool GetSerieXMinMax (double &Min, double &Max) const
 Retrieves the minimum and maximum X values of the points stored in the array.
+bool GetSerieYMinMax (double &Min, double &Max) const
 Retrieves the minimum and maximum Y values of the points stored in the array.
void SetOrdering (PointsOrdering newOrdering)
 Specifies how the points should be ordered in the array.
+PointsOrdering GetOrdering () const
 Retrieves the ordering of the points in the array.
+void ReorderPoints ()
 Refreshes the point ordering.
bool GetVisiblePoints (double dAxisMin, double dAxisMax, unsigned &uFirstPt, unsigned &uLastPt) const
 Retrieves the index of the points which are between two given values.
+T * GetInternalBuffer () const
 Returns the internal buffer of the array.
+


Detailed Description

+

template<class T>
+ class CChartPointsArray< T >

+ +Manages an array of points which supports fast resizing. +

+This class is used internally to store the data for all the points. The data is stored in a C-style array. The internal buffer can grow dynamically depending on the needs.

+The class is a template class with the template parameter being the type of the points to be stored. The points have to provide the following methods:

    +
  • +double GetXMin()
  • +
  • +double GetX()
  • +
  • +double GetXMax()
  • +
  • +double GetYMin()
  • +
  • +double GetY()
  • +
  • +double GetYMax()
  • +
+

Constructor & Destructor Documentation

+ +
+
+
+template<class T >
+ + + + + + + + + +
CChartPointsArray< T >::CChartPointsArray (unsigned  iResize = 1000  )  [inline]
+
+
+ +

+Constructor. +

+

Parameters:
+ + +
iResize The size by which the internal buffer is increased when reallocation occurs
+
+ +
+

+


Member Function Documentation

+ +
+
+
+template<class T>
+ + + + + + + + + +
void CChartPointsArray< T >::AddPoint (const T &  newPoint  )  [inline]
+
+
+ +

+Adds a new point in the array. +

+

Parameters:
+ + +
newPoint The new point to add
+
+ +
+

+ +

+
+
+template<class T>
+ + + + + + + + + + + + + + + + + + +
void CChartPointsArray< T >::AddPoints (T *  pPoints,
unsigned  uCount 
) [inline]
+
+
+ +

+Adds multiple points in the array. +

+The points are added to the ones currently stored in the array.

Parameters:
+ + + +
pPoints Array containing the points
uCount The number of points to add
+
+ +
+

+ +

+
+
+template<class T >
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bool CChartPointsArray< T >::GetVisiblePoints (double  dAxisMin,
double  dAxisMax,
unsigned &  uFirstPt,
unsigned &  uLastPt 
) const [inline]
+
+
+ +

+Retrieves the index of the points which are between two given values. +

+If the points are not ordered, uFirstPt will contain 0 and uLastPt will contain the index of the last point in the array.

Parameters:
+ + + + + +
dAxisMin The minimum value to retrieve the first visible point
dAxisMax The maximum value to retrieve the last visible point
uFirstPt This parameter will store the index of the first visible point
uLastPt This parameter will store the index of the last visible point
+
+
Returns:
false if no points are in the array.
+ +
+

+ +

+
+
+template<class T >
+ + + + + + + + + +
void CChartPointsArray< T >::SetOrdering (PointsOrdering  newOrdering  )  [inline]
+
+
+ +

+Specifies how the points should be ordered in the array. +

+This specifies if the points should be ordered on their X values, on their Y values or not ordered (kept in order they are added to the control). Ordering can improve performances a lot but makes it impossible to draw some specific curves (for instance, drawing an ellipse is only possible if no ordering is set). +

+

+ +

+
+
+template<class T>
+ + + + + + + + + + + + + + + + + + +
void CChartPointsArray< T >::SetPoints (T *  pPoints,
unsigned  uCount 
) [inline]
+
+
+ +

+Sets multiple points in the array. +

+The points currently stored in the array are first removed before adding the new points.

Parameters:
+ + + +
pPoints Array containing the new points
uCount The number of points to add
+
+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartPointsArray.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartPointsArray.inl
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_points_serie-members.html b/ChartDemo/Doc/html/class_c_chart_points_serie-members.html new file mode 100644 index 0000000..6774c81 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_points_serie-members.html @@ -0,0 +1,112 @@ + + +ChartDemo: Member List + + + + + +
+

CChartPointsSerie Member List

This is the complete list of members for CChartPointsSerie, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AddPoint(double X, double Y)CChartXYSerie
CChartSerieBase< SChartXYPoint >::AddPoint(const SChartXYPoint &newPoint)CChartSerieBase< SChartXYPoint >
AddPoints(double *pX, double *pY, unsigned Count)CChartXYSerie
CChartSerieBase< SChartXYPoint >::AddPoints(SChartXYPoint *pPoints, unsigned Count)CChartSerieBase< SChartXYPoint >
AttachCustomLabel(unsigned uPointIndex, CChartLabel< SChartXYPoint > *pLabel)CChartSerieBase< SChartXYPoint >
CChartPointsSerie(CChartCtrl *pParent)CChartPointsSerie
CChartSerie(CChartCtrl *pParent)CChartSerie
CChartSerieBase(CChartCtrl *pParent)CChartSerieBase< SChartXYPoint >
CChartXYSerie(CChartCtrl *pParent)CChartXYSerie
ClearSerie()CChartSerieBase< SChartXYPoint >
CreateBalloonLabel(unsigned uPointIndex, const TChartString &strLabelText)CChartSerieBase< SChartXYPoint >
CreateBalloonLabel(unsigned uPointIndex, CChartLabelProvider< SChartXYPoint > *pLabelProvider)CChartSerieBase< SChartXYPoint >
EnableMouseNotifications(bool bClickEnabled, bool bMoveEnabled)CChartSerie
EnableShadow(bool bEnable)CChartSerie
GetBezierControlPoints(unsigned uFirst, unsigned uLast, SChartXYPoint *&pKnots, SChartXYPoint *&pFirstControlPoints, SChartXYPoint *&pSecondControlPoints) const CChartXYSerie [protected]
GetBorderColor()CChartPointsSerie [inline]
GetColor() const CChartSerie [inline]
GetName() const CChartSerie [inline]
GetPoint(unsigned index) constCChartSerieBase< SChartXYPoint >
GetPointsCount() constCChartSerieBase< SChartXYPoint > [inline, virtual]
GetPointScreenCoord(unsigned uPointIndex)CChartSerieBase< SChartXYPoint > [virtual]
GetPointSize(int &XSize, int &YSize) const CChartPointsSerie [inline]
GetPointType() const CChartPointsSerie [inline]
GetSerieId() const CChartSerie [inline]
GetSerieXMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetSerieXScreenMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetSerieYMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetSerieYScreenMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetShadowColor() const CChartSerie [inline]
GetUserData(unsigned uPointIndex)CChartXYSerie
GetVisiblePoints(unsigned &uFirst, unsigned &uLast) constCChartSerieBase< SChartXYPoint > [protected, virtual]
GetXPointValue(unsigned PointIndex) const CChartXYSerie
GetYPointValue(unsigned PointIndex) const CChartXYSerie
IsPointOnSerie(const CPoint &screenPoint, unsigned &uIndex) const CChartPointsSerie [virtual]
IsVisible() const CChartSerie [inline]
m_bIsVisibleCChartSerie [protected]
m_bShadowCChartSerie [protected]
m_iShadowDepthCChartSerie [protected]
m_pHorizontalAxisCChartSerie [protected]
m_PlottingRectCChartSerie [protected]
m_pParentCtrlCChartSerie [protected]
m_pVerticalAxisCChartSerie [protected]
m_SerieColorCChartSerie [protected]
m_ShadowColorCChartSerie [protected]
m_strSerieNameCChartSerie [protected]
m_uLastDrawnPointCChartSerieBase< SChartXYPoint > [protected]
m_vPointsCChartSerieBase< SChartXYPoint > [protected]
NotifyMouseClickEnabled()CChartSerie [inline, protected]
NotifyMouseMoveEnabled()CChartSerie [inline, protected]
OnMouseEvent(CChartMouseListener::MouseEvent mouseEvent, const CPoint &screenPoint)CChartSerieBase< SChartXYPoint > [protected, virtual]
PointType enum nameCChartPointsSerie
ptEllipse enum value (defined in CChartPointsSerie)CChartPointsSerie
ptRectangle enum value (defined in CChartPointsSerie)CChartPointsSerie
ptTriangle enum value (defined in CChartPointsSerie)CChartPointsSerie
RefreshAutoAxes()CChartSerie [protected]
RegisterMouseListener(CChartSeriesMouseListener< SChartXYPoint > *pListener)CChartSerieBase< SChartXYPoint >
RemovePointsFromBegin(unsigned Count)CChartSerieBase< SChartXYPoint >
RemovePointsFromEnd(unsigned Count)CChartSerieBase< SChartXYPoint >
SetBorderColor(COLORREF Color)CChartPointsSerie
SetColor(COLORREF NewColor)CChartSerie
SetName(const TChartString &NewName)CChartSerie
SetPoints(double *pX, double *pY, unsigned Count)CChartXYSerie
CChartSerieBase< SChartXYPoint >::SetPoints(SChartXYPoint *pPoints, unsigned Count)CChartSerieBase< SChartXYPoint >
SetPointSize(int XSize, int YSize)CChartPointsSerie
SetPointType(PointType Type)CChartPointsSerie
SetSeriesOrdering(PointsOrdering newOrdering)CChartSerieBase< SChartXYPoint > [virtual]
SetShadowColor(COLORREF NewColor)CChartSerie
SetShadowDepth(int Depth)CChartSerie
SetUserData(unsigned uPointIndex, void *pData)CChartXYSerie
SetVisible(bool bVisible)CChartSerie
SetXPointValue(unsigned PointIndex, double NewVal)CChartXYSerie
SetYPointValue(unsigned PointIndex, double NewVal)CChartXYSerie
UnregisterMouseListener()CChartSerieBase< SChartXYPoint >
ValueToScreen(double XValue, double YValue, CPoint &ScreenPoint) const CChartSerie
XScreenToValue(long XScreenCoord) const CChartSerie
YScreenToValue(long YScreenCoord) const CChartSerie
~CChartPointsSerie()CChartPointsSerie [virtual]
~CChartSerie()CChartSerie [virtual]
~CChartSerieBase()CChartSerieBase< SChartXYPoint > [virtual]
~CChartXYSerie()CChartXYSerie [virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_points_serie.html b/ChartDemo/Doc/html/class_c_chart_points_serie.html new file mode 100644 index 0000000..ad52b02 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_points_serie.html @@ -0,0 +1,141 @@ + + +ChartDemo: CChartPointsSerie Class Reference + + + + + +
+

CChartPointsSerie Class Reference

Specialization of a CChartSerie to display a points series. +More... +

+#include <ChartPointsSerie.h> +

+

+Inheritance diagram for CChartPointsSerie:
+
+ +

+ +CChartXYSerie +CChartSerieBase< SChartXYPoint > +CChartSerie + +
+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Types

enum  PointType { ptEllipse = 0, +ptRectangle = 1, +ptTriangle = 2 + }
 The different point shapes.

Public Member Functions

+void SetPointSize (int XSize, int YSize)
 Sets the width and height of each points.
+void GetPointSize (int &XSize, int &YSize) const
 Retrieves the width and height of each points.
+void SetPointType (PointType Type)
 Sets the points shape.
+PointType GetPointType () const
 Returns the points shape.
+void SetBorderColor (COLORREF Color)
 Sets the border color of the points.
+COLORREF GetBorderColor ()
 Returns the border color of the points.
CChartPointsSerie (CChartCtrl *pParent)
 Constructor.
+virtual ~CChartPointsSerie ()
 Destructor.
bool IsPointOnSerie (const CPoint &screenPoint, unsigned &uIndex) const
 Check whether a screen point is on the series.
+


Detailed Description

+Specialization of a CChartSerie to display a points series. +

+The data points are simply displayed as independant points.


Member Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
bool CChartPointsSerie::IsPointOnSerie (const CPoint &  screenPoint,
unsigned &  uIndex 
) const [virtual]
+
+
+ +

+Check whether a screen point is on the series. +

+

Parameters:
+ + + +
screenPoint The screen point to test
uIndex If the point is close to a specific point of the series, its index is stored here.
+
+
Returns:
true if the point is on the series
+ +

Implements CChartSerie.

+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartPointsSerie.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartPointsSerie.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_points_serie.png b/ChartDemo/Doc/html/class_c_chart_points_serie.png new file mode 100644 index 0000000000000000000000000000000000000000..0ae49ea5e5802b6470b5f4177ac4a44577d85a02 GIT binary patch literal 844 zcmeAS@N?(olHy`uVBq!ia0vp^w}JQo3p0?c-@~m9q$C1-LR|m<{|{vT|9@cq{DcWW z78oBmaG?6o|0h5$V@Z%-FoVOh8)*y-OpiQW978JRyqy(T^jLwX?cvh%)AAJjF5KLE z!S3rn_Xrh6wYABUr&R=4xWz(sk;>V_RS{Cl zA6xX#bbrdXy#4T;;{}gS>`|7Svp7lV^V0>cM`HXBK3xzYe(9cAQK>C!`tCQ6CqKSa zT&N{2KfhJR^NY=#!#lK&$0mQE_CEV^`IFc;le4cM+4Ja)jTUFoy#sgG3jNsnIs0*Op`Yc{ z%e#7Zd7NA)yWH&hq2FD%*9mz9_P>}mJ7>p3ukh}3>QnOykAa1+9Mw6rKx=B(BD-QieXW56> zAK~=u${l-)8n@{Dy6}Gkd%@wSO_mn^LCdS3Ha(fj{> z)1gu~(oX*S&X|DJ-fK4*if*5{f4XUVeNMmTXSuv*N$;j{U&%k^vw4c;WnjqeXt6rv z{UE^o$JQO)+QP7K2D$57@3}3iI>ya*Mi16?D|0D+YwB|RnrfZvy!C6rEA|~PY?Jz< zWrA)W?tPrTV=3><#b+Fk$aMC}dG4GNd(r(w--ah@xA+T0+!H&yB9l1H-p}yA+ua}h z%cs+?oLAz{?!?Yg;U?FJIiCw$+M@q#c(AB^WpO~}*@H)g?&|7YxvG1vRyzEd?42q@ zb)B^G`zv4NeC!gCU4H6HS#a8ql}72(1qT?@cNEwE_{+X>X4EA61DT*a!QkoY=d#Wz Gp$Pyi9iGhq literal 0 HcmV?d00001 diff --git a/ChartDemo/Doc/html/class_c_chart_scroll_bar-members.html b/ChartDemo/Doc/html/class_c_chart_scroll_bar-members.html new file mode 100644 index 0000000..cf4e141 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_scroll_bar-members.html @@ -0,0 +1,42 @@ + + +ChartDemo: Member List + + + + + +
+

CChartScrollBar Member List

This is the complete list of members for CChartScrollBar, including all inherited members.

+ + + + + + + + + + +
CreateScrollBar(const CRect &PlottingRect)CChartScrollBar
GetAutoHide() const CChartScrollBar [inline]
GetEnabled() const CChartScrollBar [inline]
OnHScroll(UINT nSBCode, UINT nPos)CChartScrollBar
OnMouseEnter()CChartScrollBar
OnMouseLeave()CChartScrollBar
OnVScroll(UINT nSBCode, UINT nPos)CChartScrollBar
Refresh()CChartScrollBar
SetAutoHide(bool bAutoHide)CChartScrollBar [inline]
SetEnabled(bool bEnabled)CChartScrollBar [inline]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_scroll_bar.html b/ChartDemo/Doc/html/class_c_chart_scroll_bar.html new file mode 100644 index 0000000..56cc4a9 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_scroll_bar.html @@ -0,0 +1,109 @@ + + +ChartDemo: CChartScrollBar Class Reference + + + + + +
+

CChartScrollBar Class Reference

Class which manages the interaction with the axis scroll bar. +More... +

+#include <ChartScrollBar.h> +

+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

+void CreateScrollBar (const CRect &PlottingRect)
 Creates the scroll bar within a specified rectangle.
+void OnHScroll (UINT nSBCode, UINT nPos)
 Called on horizontal scrolling.
+void OnVScroll (UINT nSBCode, UINT nPos)
 Called on vertical scrolling.
+void Refresh ()
 Refreshes the scroll bar position.
+void SetEnabled (bool bEnabled)
 Enables/disables the scroll bar.
+bool GetEnabled () const
 Returns true if the scroll bar is enabled.
void SetAutoHide (bool bAutoHide)
 Enables/disables the auto-hide mode.
+bool GetAutoHide () const
 Returns true if the auto-hide mode is activated.
+void OnMouseEnter ()
 Called when the mouse enters the scroll bar area.
+void OnMouseLeave ()
 Called when the mouse leaves the scroll bar area.
+


Detailed Description

+Class which manages the interaction with the axis scroll bar. +

+This class is used internally by the CChartAxis class.


Member Function Documentation

+ +
+
+ + + + + + + + + +
void CChartScrollBar::SetAutoHide (bool  bAutoHide  )  [inline]
+
+
+ +

+Enables/disables the auto-hide mode. +

+In auto-hide mode, the scroll bar is not visible unless the mouse is over the region of the scroll bar. +

+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartScrollBar.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartScrollBar.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_serie-members.html b/ChartDemo/Doc/html/class_c_chart_serie-members.html new file mode 100644 index 0000000..eb6507e --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_serie-members.html @@ -0,0 +1,75 @@ + + +ChartDemo: Member List + + + + + +
+

CChartSerie Member List

This is the complete list of members for CChartSerie, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CChartSerie(CChartCtrl *pParent)CChartSerie
Draw(CDC *pDC)=0CChartSerie [protected, pure virtual]
DrawAll(CDC *pDC)=0CChartSerie [protected, pure virtual]
DrawLabels(CDC *pDC)=0CChartSerie [protected, pure virtual]
DrawLegend(CDC *pDC, const CRect &rectBitmap) const =0CChartSerie [protected, pure virtual]
EnableMouseNotifications(bool bClickEnabled, bool bMoveEnabled)CChartSerie
EnableShadow(bool bEnable)CChartSerie
GetColor() const CChartSerie [inline]
GetName() const CChartSerie [inline]
GetPointsCount() const =0CChartSerie [pure virtual]
GetPointScreenCoord(unsigned uPointIndex)=0CChartSerie [pure virtual]
GetSerieId() const CChartSerie [inline]
GetSerieXMinMax(double &Min, double &Max) const =0CChartSerie [pure virtual]
GetSerieXScreenMinMax(double &Min, double &Max) const =0CChartSerie [pure virtual]
GetSerieYMinMax(double &Min, double &Max) const =0CChartSerie [pure virtual]
GetSerieYScreenMinMax(double &Min, double &Max) const =0CChartSerie [pure virtual]
GetShadowColor() const CChartSerie [inline]
GetVisiblePoints(unsigned &uFirst, unsigned &uLast) const =0CChartSerie [protected, pure virtual]
IsPointOnSerie(const CPoint &screenPoint, unsigned &uIndex) const =0CChartSerie [pure virtual]
IsVisible() const CChartSerie [inline]
m_bIsVisibleCChartSerie [protected]
m_bShadowCChartSerie [protected]
m_iShadowDepthCChartSerie [protected]
m_pHorizontalAxisCChartSerie [protected]
m_PlottingRectCChartSerie [protected]
m_pParentCtrlCChartSerie [protected]
m_pVerticalAxisCChartSerie [protected]
m_SerieColorCChartSerie [protected]
m_ShadowColorCChartSerie [protected]
m_strSerieNameCChartSerie [protected]
NotifyMouseClickEnabled()CChartSerie [inline, protected]
NotifyMouseMoveEnabled()CChartSerie [inline, protected]
OnMouseEvent(CChartMouseListener::MouseEvent mouseEvent, const CPoint &screenPoint)=0CChartSerie [protected, pure virtual]
RefreshAutoAxes()CChartSerie [protected]
SetColor(COLORREF NewColor)CChartSerie
SetName(const TChartString &NewName)CChartSerie
SetShadowColor(COLORREF NewColor)CChartSerie
SetShadowDepth(int Depth)CChartSerie
SetVisible(bool bVisible)CChartSerie
ValueToScreen(double XValue, double YValue, CPoint &ScreenPoint) const CChartSerie
XScreenToValue(long XScreenCoord) const CChartSerie
YScreenToValue(long YScreenCoord) const CChartSerie
~CChartSerie()CChartSerie [virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_serie.html b/ChartDemo/Doc/html/class_c_chart_serie.html new file mode 100644 index 0000000..d5b5b0f --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_serie.html @@ -0,0 +1,737 @@ + + +ChartDemo: CChartSerie Class Reference + + + + + +
+

CChartSerie Class Reference

Abstract class that provides a common "interface" for all series in the control. +More... +

+#include <ChartSerie.h> +

+

+Inheritance diagram for CChartSerie:
+
+ +

+ +CChartSerieBase< T > +CChartSerieBase< PointType > +CChartSerieBase< SChartCandlestickPoint > +CChartSerieBase< SChartGanttPoint > +CChartSerieBase< SChartXYPoint > +CChartCandlestickSerie +CChartGanttSerie +CChartXYSerie +CChartBarSerie +CChartLineSerie +CChartPointsSerie +CChartSurfaceSerie + +
+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

+virtual unsigned GetPointsCount () const =0
 Returns the number of points in the series.
+virtual CPoint GetPointScreenCoord (unsigned uPointIndex)=0
 Returns the screen coordinate of a specific point.
virtual bool GetSerieYMinMax (double &Min, double &Max) const =0
 Retrieves the minimum and maxium Y values of the series.
virtual bool GetSerieXMinMax (double &Min, double &Max) const =0
 Retrieves the minimum and maxium X values of the series.
virtual bool GetSerieXScreenMinMax (double &Min, double &Max) const =0
 Retrieves the minimum and maxium screen X values of the series.
virtual bool GetSerieYScreenMinMax (double &Min, double &Max) const =0
 Retrieves the minimum and maxium screen Y values of the series.
+void SetName (const TChartString &NewName)
 Sets the name of the series, which is displayed in the legend.
+TChartString GetName () const
 Returns the name of the series.
void ValueToScreen (double XValue, double YValue, CPoint &ScreenPoint) const
 Converts any data point into its relative screen point.
+double YScreenToValue (long YScreenCoord) const
 Converts an Y screen value into its relative Y data value.
+double XScreenToValue (long XScreenCoord) const
 Converts an Xscreen value into its relative X data value.
CChartSerie (CChartCtrl *pParent)
 Constructor.
+virtual ~CChartSerie ()
 Destructor.
void SetVisible (bool bVisible)
 Specifies if the series is visible or not.
+bool IsVisible () const
 Returns true if the series is visible.
+COLORREF GetColor () const
 Returns the color of the series.
+void SetColor (COLORREF NewColor)
 Sets the color of the series.
+COLORREF GetShadowColor () const
 Returns the color of the shadow.
+void SetShadowColor (COLORREF NewColor)
 Sets the color of the shadow.
+void EnableShadow (bool bEnable)
 Enables or disables the shadow for the series.
+void SetShadowDepth (int Depth)
 Sepcifies the depth (in pixels) of the shadow.
virtual bool IsPointOnSerie (const CPoint &screenPoint, unsigned &uIndex) const =0
 Tests if a certain screen point is on the series.
+unsigned GetSerieId () const
 Returns the series Id.
void EnableMouseNotifications (bool bClickEnabled, bool bMoveEnabled)
 Enables or disables certain mouse notifications on the series.

Protected Member Functions

+void RefreshAutoAxes ()
 Refreshes the automatic axes associated with this series.
virtual bool GetVisiblePoints (unsigned &uFirst, unsigned &uLast) const =0
 Returns the first and last visible points of the series.
virtual void DrawLegend (CDC *pDC, const CRect &rectBitmap) const =0
 Draws the legend icon for the series.
virtual void Draw (CDC *pDC)=0
 Draws the most recent points of the series.
virtual void DrawAll (CDC *pDC)=0
 Redraws the full series.
virtual void DrawLabels (CDC *pDC)=0
 Draws the labels of the series.
virtual bool OnMouseEvent (CChartMouseListener::MouseEvent mouseEvent, const CPoint &screenPoint)=0
 Called when a mouse event is detected on the chart.
+bool NotifyMouseMoveEnabled ()
 Returns true if the series reacts on mouse moves.
+bool NotifyMouseClickEnabled ()
 Returns true if the series reacts on mouse clicks.

Protected Attributes

+CChartCtrlm_pParentCtrl
 The parent charting control.
+CChartAxism_pVerticalAxis
 The related vertical axis.
+CChartAxism_pHorizontalAxis
 The related horizontal axis.
+TChartString m_strSerieName
 The series name displayed in the legend.
+bool m_bIsVisible
 Specifies if the series is visible.
+bool m_bShadow
 Specifies if the series has shadow enabled.
+COLORREF m_SerieColor
 Color of the series.
+COLORREF m_ShadowColor
 Color of the shadow.
+int m_iShadowDepth
 Depth (in pixels) of the shadow.
+CRect m_PlottingRect
 The rectangle in which the series should be drawn.
+


Detailed Description

+Abstract class that provides a common "interface" for all series in the control. +

+The class doesn't manipulate points (the type of point is unknown at this level in the class hierarchy) but it provides all other functionalities which are independant of the point type.

+The drawing of the series is made through pure virtual functions which should be implemented by derived classes.

+Each series is identified by an Id.


Member Function Documentation

+ +
+
+ + + + + + + + + +
virtual void CChartSerie::Draw (CDC *  pDC  )  [protected, pure virtual]
+
+
+ +

+Draws the most recent points of the series. +

+This pure virtual function should be overriden by child classes. This function should only draw the points that were not previously drawn.

Parameters:
+ + +
pDC The device context used to draw
+
+ +

Implemented in CChartCandlestickSerie, and CChartGanttSerie.

+ +
+

+ +

+
+ + + + + + + + + +
virtual void CChartSerie::DrawAll (CDC *  pDC  )  [protected, pure virtual]
+
+
+ +

+Redraws the full series. +

+This pure virtual function should be overriden by child classes.

Parameters:
+ + +
pDC The device context used to draw
+
+ +

Implemented in CChartCandlestickSerie, and CChartGanttSerie.

+ +
+

+ +

+
+ + + + + + + + + +
virtual void CChartSerie::DrawLabels (CDC *  pDC  )  [protected, pure virtual]
+
+
+ +

+Draws the labels of the series. +

+This pure virtual function should be overriden by child classes.

Parameters:
+ + +
pDC The device context used to draw
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
virtual void CChartSerie::DrawLegend (CDC *  pDC,
const CRect &  rectBitmap 
) const [protected, pure virtual]
+
+
+ +

+Draws the legend icon for the series. +

+This pure virtual function should be overriden by child classes.

Parameters:
+ + + +
pDC The device context used to draw
rectBitmap The rectangle in which to draw the legend icon
+
+ +

Implemented in CChartCandlestickSerie, and CChartGanttSerie.

+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartSerie::EnableMouseNotifications (bool  bClickEnabled,
bool  bMoveEnabled 
)
+
+
+ +

+Enables or disables certain mouse notifications on the series. +

+Checking if a point is on the series could degrade performances if it has to be done for each mouse event. This function allows to disable certain notifications, in which case the test won't be done. By default the series reacts on mouse clicks but not on mouse moves.

Parameters:
+ + + +
bClickEnabled Specifies if the series reacts on mouse clicks.
bMoveEnabled Specifies if the series reacts on mouse moves.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
virtual bool CChartSerie::GetSerieXMinMax (double &  Min,
double &  Max 
) const [pure virtual]
+
+
+ +

+Retrieves the minimum and maxium X values of the series. +

+

Parameters:
+ + + +
Min Minimum value will be stored in this parameter
Max Maximum value will be stored in this parameter
+
+
Returns:
false if the series doesn't contain data or is invisible
+ +

Implemented in CChartSerieBase< T >, CChartSerieBase< SChartCandlestickPoint >, CChartSerieBase< SChartXYPoint >, CChartSerieBase< SChartGanttPoint >, and CChartSerieBase< PointType >.

+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
virtual bool CChartSerie::GetSerieXScreenMinMax (double &  Min,
double &  Max 
) const [pure virtual]
+
+
+ +

+Retrieves the minimum and maxium screen X values of the series. +

+

Parameters:
+ + + +
Min Minimum value will be stored in this parameter
Max Maximum value will be stored in this parameter
+
+
Returns:
false if the series doesn't contain data or is invisible
+ +

Implemented in CChartSerieBase< T >, CChartSerieBase< SChartCandlestickPoint >, CChartSerieBase< SChartXYPoint >, CChartSerieBase< SChartGanttPoint >, and CChartSerieBase< PointType >.

+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
virtual bool CChartSerie::GetSerieYMinMax (double &  Min,
double &  Max 
) const [pure virtual]
+
+
+ +

+Retrieves the minimum and maxium Y values of the series. +

+

Parameters:
+ + + +
Min Minimum value will be stored in this parameter
Max Maximum value will be stored in this parameter
+
+
Returns:
false if the series doesn't contain data or is invisible
+ +

Implemented in CChartSerieBase< T >, CChartSerieBase< SChartCandlestickPoint >, CChartSerieBase< SChartXYPoint >, CChartSerieBase< SChartGanttPoint >, and CChartSerieBase< PointType >.

+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
virtual bool CChartSerie::GetSerieYScreenMinMax (double &  Min,
double &  Max 
) const [pure virtual]
+
+
+ +

+Retrieves the minimum and maxium screen Y values of the series. +

+

Parameters:
+ + + +
Min Minimum value will be stored in this parameter
Max Maximum value will be stored in this parameter
+
+
Returns:
false if the series doesn't contain data or is invisible
+ +

Implemented in CChartSerieBase< T >, CChartSerieBase< SChartCandlestickPoint >, CChartSerieBase< SChartXYPoint >, CChartSerieBase< SChartGanttPoint >, and CChartSerieBase< PointType >.

+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
virtual bool CChartSerie::GetVisiblePoints (unsigned &  uFirst,
unsigned &  uLast 
) const [protected, pure virtual]
+
+
+ +

+Returns the first and last visible points of the series. +

+This function only works if ordering is enabled.

Parameters:
+ + + +
uFirst The index of the first visible point is stored in this argument
uLast The index of the last visible point is stored in this argument
+
+
Returns:
false if the series has no ordering or no data points.
+ +

Implemented in CChartSerieBase< T >, CChartSerieBase< SChartCandlestickPoint >, CChartSerieBase< SChartXYPoint >, CChartSerieBase< SChartGanttPoint >, and CChartSerieBase< PointType >.

+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
virtual bool CChartSerie::IsPointOnSerie (const CPoint &  screenPoint,
unsigned &  uIndex 
) const [pure virtual]
+
+
+ +

+Tests if a certain screen point is on the series. +

+This function should be overidden by all child classes.

Parameters:
+ + + +
screenPoint The screen point to test
uIndex If the point is close to a specific point of the series, its index is stored here.
+
+
Returns:
true if the point is on the series
+ +

Implemented in CChartBarSerie, CChartCandlestickSerie, CChartGanttSerie, CChartLineSerie, CChartPointsSerie, and CChartSurfaceSerie.

+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
virtual bool CChartSerie::OnMouseEvent (CChartMouseListener::MouseEvent  mouseEvent,
const CPoint &  screenPoint 
) [protected, pure virtual]
+
+
+ +

+Called when a mouse event is detected on the chart. +

+This pure virtual function should be overriden by child classes.

Parameters:
+ + + +
mouseEvent The event that occured on the control
screenPoint The screen point on which the event occured
+
+
Returns:
true if the event occured on the series.
+ +

Implemented in CChartSerieBase< T >, CChartSerieBase< SChartCandlestickPoint >, CChartSerieBase< SChartXYPoint >, CChartSerieBase< SChartGanttPoint >, and CChartSerieBase< PointType >.

+ +
+

+ +

+
+ + + + + + + + + +
void CChartSerie::SetVisible (bool  bVisible  ) 
+
+
+ +

+Specifies if the series is visible or not. +

+An invisible series won't affect automatic axis: it is considered as if it was not in the control. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void CChartSerie::ValueToScreen (double  XValue,
double  YValue,
CPoint &  ScreenPoint 
) const
+
+
+ +

+Converts any data point into its relative screen point. +

+

Parameters:
+ + + + +
XValue The X value of the data point
YValue The Y value of the data point
ScreenPoint The screen point will be stored in the parameter
+
+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartSerie.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartSerie.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_serie.png b/ChartDemo/Doc/html/class_c_chart_serie.png new file mode 100644 index 0000000000000000000000000000000000000000..26316dea199c11c91420a0fdc1d934c42c6d7d49 GIT binary patch literal 3251 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 literal 0 HcmV?d00001 diff --git a/ChartDemo/Doc/html/class_c_chart_serie_base-members.html b/ChartDemo/Doc/html/class_c_chart_serie_base-members.html new file mode 100644 index 0000000..ad07650 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_serie_base-members.html @@ -0,0 +1,91 @@ + + +ChartDemo: Member List + + + + + +
+

CChartSerieBase< T > Member List

This is the complete list of members for CChartSerieBase< T >, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AddPoint(const T &newPoint)CChartSerieBase< T > [inline]
AddPoints(T *pPoints, unsigned Count)CChartSerieBase< T > [inline]
AttachCustomLabel(unsigned uPointIndex, CChartLabel< T > *pLabel)CChartSerieBase< T > [inline]
CChartSerie(CChartCtrl *pParent)CChartSerie
CChartSerieBase(CChartCtrl *pParent)CChartSerieBase< T > [inline]
ClearSerie()CChartSerieBase< T > [inline]
CreateBalloonLabel(unsigned uPointIndex, const TChartString &strLabelText)CChartSerieBase< T > [inline]
CreateBalloonLabel(unsigned uPointIndex, CChartLabelProvider< T > *pLabelProvider)CChartSerieBase< T > [inline]
Draw(CDC *pDC)=0CChartSerie [protected, pure virtual]
DrawAll(CDC *pDC)=0CChartSerie [protected, pure virtual]
DrawLegend(CDC *pDC, const CRect &rectBitmap) const =0CChartSerie [protected, pure virtual]
EnableMouseNotifications(bool bClickEnabled, bool bMoveEnabled)CChartSerie
EnableShadow(bool bEnable)CChartSerie
GetColor() const CChartSerie [inline]
GetName() const CChartSerie [inline]
GetPoint(unsigned index) const CChartSerieBase< T > [inline]
GetPointsCount() const CChartSerieBase< T > [inline, virtual]
GetPointScreenCoord(unsigned uPointIndex)CChartSerieBase< T > [inline, virtual]
GetSerieId() const CChartSerie [inline]
GetSerieXMinMax(double &Min, double &Max) const CChartSerieBase< T > [inline, virtual]
GetSerieXScreenMinMax(double &Min, double &Max) const CChartSerieBase< T > [inline, virtual]
GetSerieYMinMax(double &Min, double &Max) const CChartSerieBase< T > [inline, virtual]
GetSerieYScreenMinMax(double &Min, double &Max) const CChartSerieBase< T > [inline, virtual]
GetShadowColor() const CChartSerie [inline]
GetVisiblePoints(unsigned &uFirst, unsigned &uLast) const CChartSerieBase< T > [inline, protected, virtual]
IsPointOnSerie(const CPoint &screenPoint, unsigned &uIndex) const =0CChartSerie [pure virtual]
IsVisible() const CChartSerie [inline]
m_bIsVisibleCChartSerie [protected]
m_bShadowCChartSerie [protected]
m_iShadowDepthCChartSerie [protected]
m_pHorizontalAxisCChartSerie [protected]
m_PlottingRectCChartSerie [protected]
m_pParentCtrlCChartSerie [protected]
m_pVerticalAxisCChartSerie [protected]
m_SerieColorCChartSerie [protected]
m_ShadowColorCChartSerie [protected]
m_strSerieNameCChartSerie [protected]
m_uLastDrawnPointCChartSerieBase< T > [protected]
m_vPointsCChartSerieBase< T > [protected]
NotifyMouseClickEnabled()CChartSerie [inline, protected]
NotifyMouseMoveEnabled()CChartSerie [inline, protected]
OnMouseEvent(CChartMouseListener::MouseEvent mouseEvent, const CPoint &screenPoint)CChartSerieBase< T > [inline, protected, virtual]
RefreshAutoAxes()CChartSerie [protected]
RegisterMouseListener(CChartSeriesMouseListener< T > *pListener)CChartSerieBase< T > [inline]
RemovePointsFromBegin(unsigned Count)CChartSerieBase< T > [inline]
RemovePointsFromEnd(unsigned Count)CChartSerieBase< T > [inline]
SetColor(COLORREF NewColor)CChartSerie
SetName(const TChartString &NewName)CChartSerie
SetPoints(T *pPoints, unsigned Count)CChartSerieBase< T > [inline]
SetSeriesOrdering(PointsOrdering newOrdering)CChartSerieBase< T > [inline, virtual]
SetShadowColor(COLORREF NewColor)CChartSerie
SetShadowDepth(int Depth)CChartSerie
SetVisible(bool bVisible)CChartSerie
UnregisterMouseListener()CChartSerieBase< T > [inline]
ValueToScreen(double XValue, double YValue, CPoint &ScreenPoint) const CChartSerie
XScreenToValue(long XScreenCoord) const CChartSerie
YScreenToValue(long YScreenCoord) const CChartSerie
~CChartSerie()CChartSerie [virtual]
~CChartSerieBase()CChartSerieBase< T > [inline, virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_serie_base.html b/ChartDemo/Doc/html/class_c_chart_serie_base.html new file mode 100644 index 0000000..465daa5 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_serie_base.html @@ -0,0 +1,672 @@ + + +ChartDemo: CChartSerieBase< T > Class Template Reference + + + + + +
+

CChartSerieBase< T > Class Template Reference

Base class for all series of the control. +More... +

+#include <ChartSerieBase.h> +

+

+Inheritance diagram for CChartSerieBase< T >:
+
+ +

+ +CChartSerie + +
+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

+void AddPoint (const T &newPoint)
 Adds a single data point to the series.
void AddPoints (T *pPoints, unsigned Count)
 Adds an array of points to the series.
const T & GetPoint (unsigned index) const
 Retrieves the point at the specified index.
void SetPoints (T *pPoints, unsigned Count)
 Sets an array of points to the series.
+void RemovePointsFromBegin (unsigned Count)
 Removes a certain amount of points from the begining of the series.
+void RemovePointsFromEnd (unsigned Count)
 Removes a certain amount of points from the end of the series.
+void ClearSerie ()
 Removes all points from the series.
+unsigned GetPointsCount () const
 Returns the number of points in the series.
bool GetSerieYMinMax (double &Min, double &Max) const
 Retrieves the minimum and maxium Y values of the series.
bool GetSerieXMinMax (double &Min, double &Max) const
 Retrieves the minimum and maxium X values of the series.
bool GetSerieXScreenMinMax (double &Min, double &Max) const
 Retrieves the minimum and maxium screen X values of the series.
bool GetSerieYScreenMinMax (double &Min, double &Max) const
 Retrieves the minimum and maxium screen Y values of the series.
CChartBalloonLabel< T > * CreateBalloonLabel (unsigned uPointIndex, const TChartString &strLabelText)
 Creates and attaches a balloon label on a point of the series.
CChartBalloonLabel< T > * CreateBalloonLabel (unsigned uPointIndex, CChartLabelProvider< T > *pLabelProvider)
 Creates and attaches a balloon label on a point of the series.
void AttachCustomLabel (unsigned uPointIndex, CChartLabel< T > *pLabel)
 Attaches a custom label on a point of the series.
CChartSerieBase (CChartCtrl *pParent)
 Constructor.
+virtual ~CChartSerieBase ()
 Destructor.
virtual void SetSeriesOrdering (PointsOrdering newOrdering)
 Specifies how the points should be ordered in the series.
CPoint GetPointScreenCoord (unsigned uPointIndex)
 Retrieves the screen point of a specific data point.
void RegisterMouseListener (CChartSeriesMouseListener< T > *pListener)
 Register a series mouse listener on this series.
+void UnregisterMouseListener ()
 Unregister the series mouse listener for this series.

Protected Member Functions

bool GetVisiblePoints (unsigned &uFirst, unsigned &uLast) const
 Returns the first and last visible points of the series.
+bool OnMouseEvent (CChartMouseListener::MouseEvent mouseEvent, const CPoint &screenPoint)
 Called by the control to check if an event occured on the series.

Protected Attributes

+CChartPointsArray< T > m_vPoints
 The helper class containing all the data points.
+unsigned m_uLastDrawnPoint
 Index of the last point drawn.
+


Detailed Description

+

template<class T>
+ class CChartSerieBase< T >

+ +Base class for all series of the control. +

+This class inherits from CChartSeries and introduces the concept of points through the template parameter.

+This class is much more than a simple base class. It already store all the data points and provide utility functions to manipulate them.


Member Function Documentation

+ +
+
+
+template<class T>
+ + + + + + + + + + + + + + + + + + +
void CChartSerieBase< T >::AddPoints (T *  pPoints,
unsigned  Count 
) [inline]
+
+
+ +

+Adds an array of points to the series. +

+Points which were already present in the series are kept.

Parameters:
+ + + +
pPoints Array of the new points
Count Size of the array
+
+ +
+

+ +

+
+
+template<class T>
+ + + + + + + + + + + + + + + + + + +
void CChartSerieBase< T >::AttachCustomLabel (unsigned  uPointIndex,
CChartLabel< T > *  pLabel 
) [inline]
+
+
+ +

+Attaches a custom label on a point of the series. +

+

Parameters:
+ + + +
uPointIndex The index of the point on which the label should be attached
pLabel The label to attach to the point
+
+ +
+

+ +

+
+
+template<class T>
+ + + + + + + + + + + + + + + + + + +
CChartBalloonLabel< T > * CChartSerieBase< T >::CreateBalloonLabel (unsigned  uPointIndex,
CChartLabelProvider< T > *  pLabelProvider 
) [inline]
+
+
+ +

+Creates and attaches a balloon label on a point of the series. +

+This functions specifies a CChartLabelProvider object which is used to supply the text of the label. This is useful if you want more flexibility for the text of the label (display information about the point value for instance).

Parameters:
+ + + +
uPointIndex The index of the point on which the label should be attached
pLabelProvider Object providing the text displayed on the label
+
+
Returns:
the created CChartBalloonLabel
+ +
+

+ +

+
+
+template<class T >
+ + + + + + + + + + + + + + + + + + +
CChartBalloonLabel< T > * CChartSerieBase< T >::CreateBalloonLabel (unsigned  uPointIndex,
const TChartString &  strLabelText 
) [inline]
+
+
+ +

+Creates and attaches a balloon label on a point of the series. +

+This functions specifies a static text to display in the label.

Parameters:
+ + + +
uPointIndex The index of the point on which the label should be attached
strLabelText The text of the label
+
+
Returns:
the created CChartBalloonLabel
+ +
+

+ +

+
+
+template<class T >
+ + + + + + + + + +
const T & CChartSerieBase< T >::GetPoint (unsigned  index  )  const [inline]
+
+
+ +

+Retrieves the point at the specified index. +

+

Parameters:
+ + +
index The index of the point to retrieve
+
+ +
+

+ +

+
+
+template<class T >
+ + + + + + + + + +
CPoint CChartSerieBase< T >::GetPointScreenCoord (unsigned  uPointIndex  )  [inline, virtual]
+
+
+ +

+Retrieves the screen point of a specific data point. +

+

Parameters:
+ + +
uPointIndex The index of the point for which to retrieve the screen point
+
+
Returns:
the screen point
+ +

Implements CChartSerie.

+ +
+

+ +

+
+
+template<class T >
+ + + + + + + + + + + + + + + + + + +
bool CChartSerieBase< T >::GetSerieXMinMax (double &  Min,
double &  Max 
) const [inline, virtual]
+
+
+ +

+Retrieves the minimum and maxium X values of the series. +

+

Parameters:
+ + + +
Min Minimum value will be stored in this parameter
Max Maximum value will be stored in this parameter
+
+
Returns:
false if the series doesn't contain data or is invisible
+ +

Implements CChartSerie.

+ +
+

+ +

+
+
+template<class T >
+ + + + + + + + + + + + + + + + + + +
bool CChartSerieBase< T >::GetSerieXScreenMinMax (double &  Min,
double &  Max 
) const [inline, virtual]
+
+
+ +

+Retrieves the minimum and maxium screen X values of the series. +

+

Parameters:
+ + + +
Min Minimum value will be stored in this parameter
Max Maximum value will be stored in this parameter
+
+
Returns:
false if the series doesn't contain data or is invisible
+ +

Implements CChartSerie.

+ +
+

+ +

+
+
+template<class T >
+ + + + + + + + + + + + + + + + + + +
bool CChartSerieBase< T >::GetSerieYMinMax (double &  Min,
double &  Max 
) const [inline, virtual]
+
+
+ +

+Retrieves the minimum and maxium Y values of the series. +

+

Parameters:
+ + + +
Min Minimum value will be stored in this parameter
Max Maximum value will be stored in this parameter
+
+
Returns:
false if the series doesn't contain data or is invisible
+ +

Implements CChartSerie.

+ +
+

+ +

+
+
+template<class T >
+ + + + + + + + + + + + + + + + + + +
bool CChartSerieBase< T >::GetSerieYScreenMinMax (double &  Min,
double &  Max 
) const [inline, virtual]
+
+
+ +

+Retrieves the minimum and maxium screen Y values of the series. +

+

Parameters:
+ + + +
Min Minimum value will be stored in this parameter
Max Maximum value will be stored in this parameter
+
+
Returns:
false if the series doesn't contain data or is invisible
+ +

Implements CChartSerie.

+ +
+

+ +

+
+
+template<class T >
+ + + + + + + + + + + + + + + + + + +
bool CChartSerieBase< T >::GetVisiblePoints (unsigned &  uFirst,
unsigned &  uLast 
) const [inline, protected, virtual]
+
+
+ +

+Returns the first and last visible points of the series. +

+This function only works if ordering is enabled.

Parameters:
+ + + +
uFirst The index of the first visible point is stored in this argument
uLast The index of the last visible point is stored in this argument
+
+
Returns:
false if the series has no ordering or no data points.
+ +

Implements CChartSerie.

+ +
+

+ +

+
+
+template<class T>
+ + + + + + + + + +
void CChartSerieBase< T >::RegisterMouseListener (CChartSeriesMouseListener< T > *  pListener  )  [inline]
+
+
+ +

+Register a series mouse listener on this series. +

+

Parameters:
+ + +
pListener The listener to register
+
+ +
+

+ +

+
+
+template<class T>
+ + + + + + + + + + + + + + + + + + +
void CChartSerieBase< T >::SetPoints (T *  pPoints,
unsigned  Count 
) [inline]
+
+
+ +

+Sets an array of points to the series. +

+Points which were already present in the series are discarded.

Parameters:
+ + + +
pPoints Array of the new points
Count Size of the array
+
+ +
+

+ +

+
+
+template<class T >
+ + + + + + + + + +
void CChartSerieBase< T >::SetSeriesOrdering (PointsOrdering  newOrdering  )  [inline, virtual]
+
+
+ +

+Specifies how the points should be ordered in the series. +

+This specifies if the points should be ordered on their X values, on their Y values or not ordered (kept in order they are added to the control). Ordering can improve performances a lot but makes it impossible to draw some specific curves (for instance, drawing an ellipse is only possible if no ordering is set). +

Reimplemented in CChartSurfaceSerie.

+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartSerieBase.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartSerieBase.inl
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_serie_base.png b/ChartDemo/Doc/html/class_c_chart_serie_base.png new file mode 100644 index 0000000000000000000000000000000000000000..ab84c515d8c828c9d2d2e7c1d503b057ad0fee57 GIT binary patch literal 460 zcmV;-0WmP8E7DxOw91V}^iOzxpUC@yr#&QTFJn2Y!%8?wC_N4ddB1`I^9(9eB z6;!Ts9L(GwOmLl}YdFeDMNb{Or8@RvUmMP`zMA((mt#}b(Ds%0@9T_B&bx9(eRp=) zZBNnvaXyx7ahBzFDbCgQH93LvlXE?e3^5KoMDpb9;SlDH#RY2e2;D46zu{`O zraKO!80Fk>G;E&Pgv|*JhunihAmU&au^i4LB25`bLoay6feg)v{Y+#@xmpUPAjsM= zcR1#9Ev0fP$L6DMIcU{G+~tsPof?U=Fi$F@C%v=W^+nv{IECxjJr!zS9zD?0>}$hW z``R;~=KayW$OfPT5iTize}wtzz6RLjyentWcjpJtn+oq9fa)gz0000 + +ChartDemo: Member List + + + + + +
+

CChartSeriesMouseListener< PointType > Member List

This is the complete list of members for CChartSeriesMouseListener< PointType >, including all inherited members.

+ + + +
CChartSeriesMouseListener()CChartSeriesMouseListener< PointType > [inline]
OnMouseEventSeries(CChartMouseListener::MouseEvent mouseEvent, CPoint point, CChartSerieBase< PointType > *pSerie, unsigned uPointIndex)CChartSeriesMouseListener< PointType > [inline, virtual]
~CChartSeriesMouseListener()CChartSeriesMouseListener< PointType > [inline, virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_series_mouse_listener.html b/ChartDemo/Doc/html/class_c_chart_series_mouse_listener.html new file mode 100644 index 0000000..4be984f --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_series_mouse_listener.html @@ -0,0 +1,115 @@ + + +ChartDemo: CChartSeriesMouseListener< PointType > Class Template Reference + + + + + +
+

CChartSeriesMouseListener< PointType > Class Template Reference

Listener for mouse events occuring on a series. +More... +

+#include <ChartSeriesMouseListener.h> +

+ +

+List of all members. + + + + + + + + + + + +

Public Member Functions

CChartSeriesMouseListener ()
 Constructor.
+virtual ~CChartSeriesMouseListener ()
 Destructor.
virtual void OnMouseEventSeries (CChartMouseListener::MouseEvent mouseEvent, CPoint point, CChartSerieBase< PointType > *pSerie, unsigned uPointIndex)
 Virtual function to implement in order to be notified when a mouse event occurs on a series.
+


Detailed Description

+

template<class PointType>
+ class CChartSeriesMouseListener< PointType >

+ +Listener for mouse events occuring on a series. +

+This is an interface which must be implemented in order to receive mouse notifications. You can then register your class with the chart control by calling RegisterMouseListener.


Member Function Documentation

+ +
+
+
+template<class PointType>
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
virtual void CChartSeriesMouseListener< PointType >::OnMouseEventSeries (CChartMouseListener::MouseEvent  mouseEvent,
CPoint  point,
CChartSerieBase< PointType > *  pSerie,
unsigned  uPointIndex 
) [inline, virtual]
+
+
+ +

+Virtual function to implement in order to be notified when a mouse event occurs on a series. +

+

Parameters:
+ + + + + +
mouseEvent The mouse event which occured
point The screen point on which the event occured
pSerie The series on which the event occured
uPointIndex The index of the point on which the event occured. In case the event did not occur on a specific point but on the series itself (e.g. clicking between two points on a line series), INVALID_POINT is passed for this parameter.
+
+ +
+

+


The documentation for this class was generated from the following file: +
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_standard_axis-members.html b/ChartDemo/Doc/html/class_c_chart_standard_axis-members.html new file mode 100644 index 0000000..9749166 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_standard_axis-members.html @@ -0,0 +1,93 @@ + + +ChartDemo: Member List + + + + + +
+

CChartStandardAxis Member List

This is the complete list of members for CChartStandardAxis, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CChartAxis()CChartAxis
EAxisAutoModes enum nameCChartAxis
EnableScrollBar(bool bEnabled)CChartAxis
FullAutomatic enum valueCChartAxis
GetAutoHideScrollBar() const CChartAxis
GetAutomaticMode() const CChartAxis [inline]
GetAxisLenght() const CChartAxis [protected]
GetGrid() const CChartAxis [inline]
GetLabel() const CChartAxis [inline]
GetMinMax(double &Minimum, double &Maximum) const CChartAxis [inline]
GetPosition()CChartAxis
GetScrollbarSteps(int &iTotalSteps, int &iCurrentStep)CChartAxis [protected, virtual]
GetSeriesMinMax(double &Minimum, double &Maximum)CChartAxis [protected]
GetSeriesScreenMinMax(double &Minimum, double &Maximum)CChartAxis [protected]
GetTextColor() const CChartAxis [inline]
GetTickIncrement() const CChartStandardAxis [inline]
IsAutomatic() const CChartAxis [inline]
IsHorizontal() const CChartAxis [inline]
IsInverted() const CChartAxis [inline]
IsPointInside(const CPoint &screenPoint) const CChartAxis
IsVisible() const CChartAxis [inline]
m_AutoModeCChartAxis [protected]
m_AxisRectCChartAxis [protected]
m_bAutoTicksCChartAxis [protected]
m_bDiscreteCChartAxis [protected]
m_bIsHorizontalCChartAxis [protected]
m_bIsInvertedCChartAxis [protected]
m_bIsSecondaryCChartAxis [protected]
m_bIsVisibleCChartAxis [protected]
m_EndPosCChartAxis [protected]
m_MaxValueCChartAxis [protected]
m_MinValueCChartAxis [protected]
m_pParentCtrlCChartAxis [protected]
m_StartPosCChartAxis [protected]
m_UnzoomMaxCChartAxis [protected]
m_UnzoomMinCChartAxis [protected]
NotAutomatic enum valueCChartAxis
PanAxis(long PanStart, long PanEnd)CChartAxis [protected, virtual]
ScreenAutomatic enum valueCChartAxis
ScreenToValue(long ScreenVal) const CChartAxis [virtual]
ScrollBarEnabled() const CChartAxis [inline]
SetAutoHideScrollBar(bool bAutoHide)CChartAxis
SetAutomatic(bool bAutomatic)CChartAxis
SetAutomaticMode(EAxisAutoModes AutoMode)CChartAxis
SetAxisColor(COLORREF NewColor)CChartAxis
SetAxisToScrollStep(int iPreviousStep, int iCurrentStep, bool bScrollInverted)CChartAxis [protected, virtual]
SetDiscrete(bool bDiscrete)CChartAxis [virtual]
SetFont(int nPointSize, const TChartString &strFaceName)CChartAxis
SetInverted(bool bInverted)CChartAxis
SetMarginSize(bool bAuto, int iNewSize)CChartAxis
SetMinMax(double Minimum, double Maximum)CChartAxis
SetPanZoomEnabled(bool bEnabled)CChartAxis [inline]
SetTextColor(COLORREF NewColor)CChartAxis
SetTickIncrement(bool bAuto, double newIncrement)CChartStandardAxis
SetVisible(bool bVisible)CChartAxis
SetZoomLimit(double dLimit)CChartAxis [inline]
SetZoomMinMax(double Minimum, double Maximum)CChartAxis [protected, virtual]
UndoZoom()CChartAxis [protected]
ValueToScreen(double Value) const CChartAxis
ValueToScreenStandard(double Value) const CChartAxis [protected, virtual]
~CChartAxis()CChartAxis [virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_standard_axis.html b/ChartDemo/Doc/html/class_c_chart_standard_axis.html new file mode 100644 index 0000000..7b1a4b5 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_standard_axis.html @@ -0,0 +1,119 @@ + + +ChartDemo: CChartStandardAxis Class Reference + + + + + +
+

CChartStandardAxis Class Reference

Specialization of a CChartAxis class to display standard values. +More... +

+#include <ChartStandardAxis.h> +

+

+Inheritance diagram for CChartStandardAxis:
+
+ +

+ +CChartAxis + +
+ +

+List of all members. + + + + + + + + +

Public Member Functions

void SetTickIncrement (bool bAuto, double newIncrement)
 Sets the tick increment.
double GetTickIncrement () const
 Gets the tick increment.
+


Detailed Description

+Specialization of a CChartAxis class to display standard values.

Member Function Documentation

+ +
+
+ + + + + + + + +
double CChartStandardAxis::GetTickIncrement (  )  const [inline]
+
+
+ +

+Gets the tick increment. +

+The tick increment is the value between two adjacents ticks on the axis. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartStandardAxis::SetTickIncrement (bool  bAuto,
double  newIncrement 
)
+
+
+ +

+Sets the tick increment. +

+The tick increment is the value between two adjacents ticks on the axis.

Parameters:
+ + + +
bAuto Specifies if the tick increment is automatically calculated.
newIncrement The tick increment to use in manual mode.
+
+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartStandardAxis.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartStandardAxis.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_standard_axis.png b/ChartDemo/Doc/html/class_c_chart_standard_axis.png new file mode 100644 index 0000000000000000000000000000000000000000..56b202adcd38807e54099e82f9e2d581cedbff93 GIT binary patch literal 457 zcmeAS@N?(olHy`uVBq!ia0vp^^*|iJ!VDx2Wo|zVq$C1-LR|m<{|{vT|9@cq{DcWW z78oBmaG?6o|0h5$V@Z%-FoVOh8)-mxyr+v}NJQ(~Dc*TU3^>{njk7=Sz7Y;F7JsGn z-QJ0j-F}wOV$_6DX!p77&*o%Bg9C@`R0z2NWCmS-aK7&b86V7PYVR`WCKfYuD% xkZ?c7;_qKXOd2;bWpOH-G3GN#{9Rkm_~_0n#`zv!fx*te;OXk;vd$@?2>`&MyD$I% literal 0 HcmV?d00001 diff --git a/ChartDemo/Doc/html/class_c_chart_surface_serie-members.html b/ChartDemo/Doc/html/class_c_chart_surface_serie-members.html new file mode 100644 index 0000000..42f07c8 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_surface_serie-members.html @@ -0,0 +1,114 @@ + + +ChartDemo: Member List + + + + + +
+

CChartSurfaceSerie Member List

This is the complete list of members for CChartSurfaceSerie, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AddPoint(double X, double Y)CChartXYSerie
CChartSerieBase< SChartXYPoint >::AddPoint(const SChartXYPoint &newPoint)CChartSerieBase< SChartXYPoint >
AddPoints(double *pX, double *pY, unsigned Count)CChartXYSerie
CChartSerieBase< SChartXYPoint >::AddPoints(SChartXYPoint *pPoints, unsigned Count)CChartSerieBase< SChartXYPoint >
AttachCustomLabel(unsigned uPointIndex, CChartLabel< SChartXYPoint > *pLabel)CChartSerieBase< SChartXYPoint >
CChartSerie(CChartCtrl *pParent)CChartSerie
CChartSerieBase(CChartCtrl *pParent)CChartSerieBase< SChartXYPoint >
CChartSurfaceSerie(CChartCtrl *pParent)CChartSurfaceSerie
CChartXYSerie(CChartCtrl *pParent)CChartXYSerie
ClearSerie()CChartSerieBase< SChartXYPoint >
CreateBalloonLabel(unsigned uPointIndex, const TChartString &strLabelText)CChartSerieBase< SChartXYPoint >
CreateBalloonLabel(unsigned uPointIndex, CChartLabelProvider< SChartXYPoint > *pLabelProvider)CChartSerieBase< SChartXYPoint >
EnableMouseNotifications(bool bClickEnabled, bool bMoveEnabled)CChartSerie
EnableShadow(bool bEnable)CChartSerie
FillStyle enum nameCChartSurfaceSerie
fsHatchCross enum value (defined in CChartSurfaceSerie)CChartSurfaceSerie
fsHatchDiagCross enum value (defined in CChartSurfaceSerie)CChartSurfaceSerie
fsHatchDownDiag enum value (defined in CChartSurfaceSerie)CChartSurfaceSerie
fsHatchHorizontal enum value (defined in CChartSurfaceSerie)CChartSurfaceSerie
fsHatchUpDiag enum value (defined in CChartSurfaceSerie)CChartSurfaceSerie
fsHatchVertical enum value (defined in CChartSurfaceSerie)CChartSurfaceSerie
fsSolid enum value (defined in CChartSurfaceSerie)CChartSurfaceSerie
GetBezierControlPoints(unsigned uFirst, unsigned uLast, SChartXYPoint *&pKnots, SChartXYPoint *&pFirstControlPoints, SChartXYPoint *&pSecondControlPoints) const CChartXYSerie [protected]
GetColor() const CChartSerie [inline]
GetFillStyle() const CChartSurfaceSerie [inline]
GetHorizontal() const CChartSurfaceSerie [inline]
GetName() const CChartSerie [inline]
GetPoint(unsigned index) constCChartSerieBase< SChartXYPoint >
GetPointsCount() constCChartSerieBase< SChartXYPoint > [inline, virtual]
GetPointScreenCoord(unsigned uPointIndex)CChartSerieBase< SChartXYPoint > [virtual]
GetSerieId() const CChartSerie [inline]
GetSerieXMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetSerieXScreenMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetSerieYMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetSerieYScreenMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetShadowColor() const CChartSerie [inline]
GetUserData(unsigned uPointIndex)CChartXYSerie
GetVisiblePoints(unsigned &uFirst, unsigned &uLast) constCChartSerieBase< SChartXYPoint > [protected, virtual]
GetXPointValue(unsigned PointIndex) const CChartXYSerie
GetYPointValue(unsigned PointIndex) const CChartXYSerie
IsPointOnSerie(const CPoint &screenPoint, unsigned &uIndex) const CChartSurfaceSerie [virtual]
IsVisible() const CChartSerie [inline]
m_bIsVisibleCChartSerie [protected]
m_bShadowCChartSerie [protected]
m_iShadowDepthCChartSerie [protected]
m_pHorizontalAxisCChartSerie [protected]
m_PlottingRectCChartSerie [protected]
m_pParentCtrlCChartSerie [protected]
m_pVerticalAxisCChartSerie [protected]
m_SerieColorCChartSerie [protected]
m_ShadowColorCChartSerie [protected]
m_strSerieNameCChartSerie [protected]
m_uLastDrawnPointCChartSerieBase< SChartXYPoint > [protected]
m_vPointsCChartSerieBase< SChartXYPoint > [protected]
NotifyMouseClickEnabled()CChartSerie [inline, protected]
NotifyMouseMoveEnabled()CChartSerie [inline, protected]
OnMouseEvent(CChartMouseListener::MouseEvent mouseEvent, const CPoint &screenPoint)CChartSerieBase< SChartXYPoint > [protected, virtual]
RefreshAutoAxes()CChartSerie [protected]
RegisterMouseListener(CChartSeriesMouseListener< SChartXYPoint > *pListener)CChartSerieBase< SChartXYPoint >
RemovePointsFromBegin(unsigned Count)CChartSerieBase< SChartXYPoint >
RemovePointsFromEnd(unsigned Count)CChartSerieBase< SChartXYPoint >
SetColor(COLORREF NewColor)CChartSerie
SetFillStyle(FillStyle NewStyle)CChartSurfaceSerie
SetHorizontal(bool bHoriz)CChartSurfaceSerie
SetName(const TChartString &NewName)CChartSerie
SetPoints(double *pX, double *pY, unsigned Count)CChartXYSerie
CChartSerieBase< SChartXYPoint >::SetPoints(SChartXYPoint *pPoints, unsigned Count)CChartSerieBase< SChartXYPoint >
SetSeriesOrdering(PointsOrdering)CChartSurfaceSerie [virtual]
SetShadowColor(COLORREF NewColor)CChartSerie
SetShadowDepth(int Depth)CChartSerie
SetUserData(unsigned uPointIndex, void *pData)CChartXYSerie
SetVisible(bool bVisible)CChartSerie
SetXPointValue(unsigned PointIndex, double NewVal)CChartXYSerie
SetYPointValue(unsigned PointIndex, double NewVal)CChartXYSerie
UnregisterMouseListener()CChartSerieBase< SChartXYPoint >
ValueToScreen(double XValue, double YValue, CPoint &ScreenPoint) const CChartSerie
XScreenToValue(long XScreenCoord) const CChartSerie
YScreenToValue(long YScreenCoord) const CChartSerie
~CChartSerie()CChartSerie [virtual]
~CChartSerieBase()CChartSerieBase< SChartXYPoint > [virtual]
~CChartSurfaceSerie()CChartSurfaceSerie [virtual]
~CChartXYSerie()CChartXYSerie [virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_surface_serie.html b/ChartDemo/Doc/html/class_c_chart_surface_serie.html new file mode 100644 index 0000000..e6104a5 --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_surface_serie.html @@ -0,0 +1,188 @@ + + +ChartDemo: CChartSurfaceSerie Class Reference + + + + + +
+

CChartSurfaceSerie Class Reference

Specialization of a CChartSerie to display a surface series. +More... +

+#include <ChartSurfaceSerie.h> +

+

+Inheritance diagram for CChartSurfaceSerie:
+
+ +

+ +CChartXYSerie +CChartSerieBase< SChartXYPoint > +CChartSerie + +
+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Types

enum  FillStyle {
+  fsSolid = 0, +fsHatchDownDiag, +fsHatchUpDiag, +fsHatchCross, +
+  fsHatchDiagCross, +fsHatchHorizontal, +fsHatchVertical +
+ }
 The different fill styles.

Public Member Functions

CChartSurfaceSerie (CChartCtrl *pParent)
 Constructor.
+virtual ~CChartSurfaceSerie ()
 Destructor.
+void SetFillStyle (FillStyle NewStyle)
 Sets the fill style.
+FillStyle GetFillStyle () const
 Returns the fill style.
void SetHorizontal (bool bHoriz)
 Sets the series in horizontal or vertical mode.
+bool GetHorizontal () const
 Returns true if the series is in horizontal mode.
bool IsPointOnSerie (const CPoint &screenPoint, unsigned &uIndex) const
 Check whether a screen point is on the series.
void SetSeriesOrdering (PointsOrdering)
 Specifies how the points should be ordered in the series.
+


Detailed Description

+Specialization of a CChartSerie to display a surface series. +

+A surface can be horizontal (default) or vertical: this defines how the filling of the surface is done. For a horizontal surface, the filling is done between the points and the associated horizontal axis and for a vertical surface, the filling is done between the points and the associated vertical axis. The series can be associated with a secondary axis. For example, if the surface series is horizontal and is associated with the top axis (secondary axis), the filling is done between the top axis and the points.


Member Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
bool CChartSurfaceSerie::IsPointOnSerie (const CPoint &  screenPoint,
unsigned &  uIndex 
) const [virtual]
+
+
+ +

+Check whether a screen point is on the series. +

+This function returns true if the screen point is on the surface. If the screen point is also close to a specific point of the series, the index of the point is stored in the uIndex parameter. Otherwise, this parameter contains INVALID_POINT.

Parameters:
+ + + +
screenPoint The screen point to test
uIndex If the point is close to a specific point of the series, its index is stored here.
+
+
Returns:
true if the point is on the series
+ +

Implements CChartSerie.

+ +
+

+ +

+
+ + + + + + + + + +
void CChartSurfaceSerie::SetHorizontal (bool  bHoriz  ) 
+
+
+ +

+Sets the series in horizontal or vertical mode. +

+If the series is in horizontal mode, the filling will be done between the data points and the horizontal axis. +

+

+ +

+
+ + + + + + + + + +
void CChartSurfaceSerie::SetSeriesOrdering (PointsOrdering  newOrdering  )  [virtual]
+
+
+ +

+Specifies how the points should be ordered in the series. +

+This specifies if the points should be ordered on their X values, on their Y values or not ordered (kept in order they are added to the control). Ordering can improve performances a lot but makes it impossible to draw some specific curves (for instance, drawing an ellipse is only possible if no ordering is set). +

Reimplemented from CChartSerieBase< SChartXYPoint >.

+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartSurfaceSerie.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartSurfaceSerie.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_surface_serie.png b/ChartDemo/Doc/html/class_c_chart_surface_serie.png new file mode 100644 index 0000000000000000000000000000000000000000..da63a13648751fadf5246651f413ab84c6be0d18 GIT binary patch literal 860 zcmV-i1Ec(jP);_Awl!ma6Ishb9Oze=!HG!V;yON+CYwn^*Q;yS7XI&?bZIWsF|B+hBu z7^##=aLDJy&N(l>z-?9uY93ljPCo>5(Z5_=1M`g2^C&0Cc?GvwC9rE}*T&{zoO~*W zc^T6p1-*70>RdDLH*UR3AXz<O5{MmgtIX!UW9^G$a$)IWQJ%|BWu9li0S8<_9pNQ#s3W{B z?&8V>4mjX|0}eRgfCCP=eLMMa^4iblz@3WQD;G%3qIdlcy93uqj|}>r0e4ZH zi%N>hom}G{53|wIGkZLZ^AQwLzQMUVpj&$O*dETAL)>w3xEPEla@rnWDIT)sd^f3w z*VaGcVo=GE^ldn=+th4_Q}J+nf%f5a*PAmLZn8Li?sY!*55hUhxExOEB~qNK$4&MT z + +ChartDemo: Member List + + + + + +
+

CChartTitle Member List

This is the complete list of members for CChartTitle, including all inherited members.

+ + + + + + + + + + + + + +
AddString(const TChartString &NewString)CChartTitle
GetColor() const CChartTitle [inline]
GetString(size_t Index) const CChartTitle
GetStringCount() const CChartTitle
IsPointInside(const CPoint &screenPoint) const CChartTitle
IsVisible() const CChartTitle [inline]
RemoveAll()CChartTitle
SetColor(COLORREF NewColor)CChartTitle
SetFont(int iPointSize, const TChartString &strFaceName)CChartTitle
SetFont(const CChartFont &newFont)CChartTitle
SetLineFont(int iLineIndex, int iPointSize, const TChartString &strFaceName)CChartTitle
SetLineFont(int iLineIndex, const CChartFont &newFont)CChartTitle
SetVisible(bool bVisible)CChartTitle [inline]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_title.html b/ChartDemo/Doc/html/class_c_chart_title.html new file mode 100644 index 0000000..2797a9e --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_title.html @@ -0,0 +1,241 @@ + + +ChartDemo: CChartTitle Class Reference + + + + + +
+

CChartTitle Class Reference

This class is responsible for the titles displayed on the control. +More... +

+#include <ChartTitle.h> +

+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

+size_t GetStringCount () const
 Returns the number of lines in the title.
+TChartString GetString (size_t Index) const
 Returns a specific line, specified by its index.
+void AddString (const TChartString &NewString)
 Adds a new line to the title.
+void RemoveAll ()
 Removes all the lines displayed in the title.
void SetFont (int iPointSize, const TChartString &strFaceName)
 Sets the default font.
void SetFont (const CChartFont &newFont)
 Sets the default font.
void SetLineFont (int iLineIndex, int iPointSize, const TChartString &strFaceName)
 Sets the font for a specific line.
void SetLineFont (int iLineIndex, const CChartFont &newFont)
 Sets the font for a specific line.
+void SetVisible (bool bVisible)
 Shows/hides the title.
+bool IsVisible () const
 Returns true if the title is visible.
+COLORREF GetColor () const
 Returns the text color.
+void SetColor (COLORREF NewColor)
 Sets the text color.
+BOOL IsPointInside (const CPoint &screenPoint) const
 Returns true if a screen point is in the region of the title.
+


Detailed Description

+This class is responsible for the titles displayed on the control. +

+Several lines can be displayed in the title, each one possibly with its own font. It is retrieved by calling the GetTitle() function from the CChartCtrl class.


Member Function Documentation

+ +
+
+ + + + + + + + + +
void CChartTitle::SetFont (const CChartFont newFont  ) 
+
+
+ +

+Sets the default font. +

+This function allows to set extended font style by passing a CChartFont object.

Parameters:
+ + +
newFont The new font.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartTitle::SetFont (int  iPointSize,
const TChartString &  strFaceName 
)
+
+
+ +

+Sets the default font. +

+

Parameters:
+ + + +
iPointSize The font point size.
strFaceName The font face name ("Times New Roman", "Arial", ...)
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartTitle::SetLineFont (int  iLineIndex,
const CChartFont newFont 
)
+
+
+ +

+Sets the font for a specific line. +

+This function allows to set extended font style by passing a CChartFont object.

Parameters:
+ + + +
iLineIndex The index of the line to set the font.
newFont The new font.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void CChartTitle::SetLineFont (int  iLineIndex,
int  iPointSize,
const TChartString &  strFaceName 
)
+
+
+ +

+Sets the font for a specific line. +

+

Parameters:
+ + + + +
iLineIndex The index of the line to set the font.
iPointSize The font point size.
strFaceName The font face name ("Times New Roman", "Arial", ...)
+
+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartTitle.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartTitle.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_x_y_serie-members.html b/ChartDemo/Doc/html/class_c_chart_x_y_serie-members.html new file mode 100644 index 0000000..ca582bb --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_x_y_serie-members.html @@ -0,0 +1,103 @@ + + +ChartDemo: Member List + + + + + +
+

CChartXYSerie Member List

This is the complete list of members for CChartXYSerie, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AddPoint(double X, double Y)CChartXYSerie
CChartSerieBase< SChartXYPoint >::AddPoint(const SChartXYPoint &newPoint)CChartSerieBase< SChartXYPoint >
AddPoints(double *pX, double *pY, unsigned Count)CChartXYSerie
CChartSerieBase< SChartXYPoint >::AddPoints(SChartXYPoint *pPoints, unsigned Count)CChartSerieBase< SChartXYPoint >
AttachCustomLabel(unsigned uPointIndex, CChartLabel< SChartXYPoint > *pLabel)CChartSerieBase< SChartXYPoint >
CChartSerie(CChartCtrl *pParent)CChartSerie
CChartSerieBase(CChartCtrl *pParent)CChartSerieBase< SChartXYPoint >
CChartXYSerie(CChartCtrl *pParent)CChartXYSerie
ClearSerie()CChartSerieBase< SChartXYPoint >
CreateBalloonLabel(unsigned uPointIndex, const TChartString &strLabelText)CChartSerieBase< SChartXYPoint >
CreateBalloonLabel(unsigned uPointIndex, CChartLabelProvider< SChartXYPoint > *pLabelProvider)CChartSerieBase< SChartXYPoint >
Draw(CDC *pDC)=0CChartSerie [protected, pure virtual]
DrawAll(CDC *pDC)=0CChartSerie [protected, pure virtual]
DrawLegend(CDC *pDC, const CRect &rectBitmap) const =0CChartSerie [protected, pure virtual]
EnableMouseNotifications(bool bClickEnabled, bool bMoveEnabled)CChartSerie
EnableShadow(bool bEnable)CChartSerie
GetBezierControlPoints(unsigned uFirst, unsigned uLast, SChartXYPoint *&pKnots, SChartXYPoint *&pFirstControlPoints, SChartXYPoint *&pSecondControlPoints) const CChartXYSerie [protected]
GetColor() const CChartSerie [inline]
GetName() const CChartSerie [inline]
GetPoint(unsigned index) constCChartSerieBase< SChartXYPoint >
GetPointsCount() constCChartSerieBase< SChartXYPoint > [inline, virtual]
GetPointScreenCoord(unsigned uPointIndex)CChartSerieBase< SChartXYPoint > [virtual]
GetSerieId() const CChartSerie [inline]
GetSerieXMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetSerieXScreenMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetSerieYMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetSerieYScreenMinMax(double &Min, double &Max) constCChartSerieBase< SChartXYPoint > [virtual]
GetShadowColor() const CChartSerie [inline]
GetUserData(unsigned uPointIndex)CChartXYSerie
GetVisiblePoints(unsigned &uFirst, unsigned &uLast) constCChartSerieBase< SChartXYPoint > [protected, virtual]
GetXPointValue(unsigned PointIndex) const CChartXYSerie
GetYPointValue(unsigned PointIndex) const CChartXYSerie
IsPointOnSerie(const CPoint &screenPoint, unsigned &uIndex) const =0CChartSerie [pure virtual]
IsVisible() const CChartSerie [inline]
m_bIsVisibleCChartSerie [protected]
m_bShadowCChartSerie [protected]
m_iShadowDepthCChartSerie [protected]
m_pHorizontalAxisCChartSerie [protected]
m_PlottingRectCChartSerie [protected]
m_pParentCtrlCChartSerie [protected]
m_pVerticalAxisCChartSerie [protected]
m_SerieColorCChartSerie [protected]
m_ShadowColorCChartSerie [protected]
m_strSerieNameCChartSerie [protected]
m_uLastDrawnPointCChartSerieBase< SChartXYPoint > [protected]
m_vPointsCChartSerieBase< SChartXYPoint > [protected]
NotifyMouseClickEnabled()CChartSerie [inline, protected]
NotifyMouseMoveEnabled()CChartSerie [inline, protected]
OnMouseEvent(CChartMouseListener::MouseEvent mouseEvent, const CPoint &screenPoint)CChartSerieBase< SChartXYPoint > [protected, virtual]
RefreshAutoAxes()CChartSerie [protected]
RegisterMouseListener(CChartSeriesMouseListener< SChartXYPoint > *pListener)CChartSerieBase< SChartXYPoint >
RemovePointsFromBegin(unsigned Count)CChartSerieBase< SChartXYPoint >
RemovePointsFromEnd(unsigned Count)CChartSerieBase< SChartXYPoint >
SetColor(COLORREF NewColor)CChartSerie
SetName(const TChartString &NewName)CChartSerie
SetPoints(double *pX, double *pY, unsigned Count)CChartXYSerie
CChartSerieBase< SChartXYPoint >::SetPoints(SChartXYPoint *pPoints, unsigned Count)CChartSerieBase< SChartXYPoint >
SetSeriesOrdering(PointsOrdering newOrdering)CChartSerieBase< SChartXYPoint > [virtual]
SetShadowColor(COLORREF NewColor)CChartSerie
SetShadowDepth(int Depth)CChartSerie
SetUserData(unsigned uPointIndex, void *pData)CChartXYSerie
SetVisible(bool bVisible)CChartSerie
SetXPointValue(unsigned PointIndex, double NewVal)CChartXYSerie
SetYPointValue(unsigned PointIndex, double NewVal)CChartXYSerie
UnregisterMouseListener()CChartSerieBase< SChartXYPoint >
ValueToScreen(double XValue, double YValue, CPoint &ScreenPoint) const CChartSerie
XScreenToValue(long XScreenCoord) const CChartSerie
YScreenToValue(long YScreenCoord) const CChartSerie
~CChartSerie()CChartSerie [virtual]
~CChartSerieBase()CChartSerieBase< SChartXYPoint > [virtual]
~CChartXYSerie()CChartXYSerie [virtual]

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_x_y_serie.html b/ChartDemo/Doc/html/class_c_chart_x_y_serie.html new file mode 100644 index 0000000..149bd7f --- /dev/null +++ b/ChartDemo/Doc/html/class_c_chart_x_y_serie.html @@ -0,0 +1,377 @@ + + +ChartDemo: CChartXYSerie Class Reference + + + + + +
+

CChartXYSerie Class Reference

Specialization of a CChartSerieBase for series having data with an X and an Y value. +More... +

+#include <ChartXYSerie.h> +

+

+Inheritance diagram for CChartXYSerie:
+
+ +

+ +CChartSerieBase< SChartXYPoint > +CChartSerie +CChartBarSerie +CChartLineSerie +CChartPointsSerie +CChartSurfaceSerie + +
+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

CChartXYSerie (CChartCtrl *pParent)
 Constructor.
+virtual ~CChartXYSerie ()
 Destructor.
+void AddPoint (double X, double Y)
 Adds a single data point to the series.
void AddPoints (double *pX, double *pY, unsigned Count)
 Adds an array of points to the series.
void SetPoints (double *pX, double *pY, unsigned Count)
 Sets an array of points to the series.
+double GetYPointValue (unsigned PointIndex) const
 Returns the Y value of a specific point in the series.
+double GetXPointValue (unsigned PointIndex) const
 Returns the X value of a specific point in the series.
void SetYPointValue (unsigned PointIndex, double NewVal)
 Sets the Y value of a specific point in the series.
void SetXPointValue (unsigned PointIndex, double NewVal)
 Sets the X value of a specific point in the series.
void SetUserData (unsigned uPointIndex, void *pData)
 Sets user data for a specific point.
void * GetUserData (unsigned uPointIndex)
 Retrieves user data for a specific point.

Protected Member Functions

void GetBezierControlPoints (unsigned uFirst, unsigned uLast, SChartXYPoint *&pKnots, SChartXYPoint *&pFirstControlPoints, SChartXYPoint *&pSecondControlPoints) const
 Retrieves the control points of a bezier curve fitting the points stored in the array.
+


Detailed Description

+Specialization of a CChartSerieBase for series having data with an X and an Y value. +

+This class is abstract and has to be implemented for specific series. It already provides features which are common to all series with points having an X and an Y value. Examples of such series are: point series, line series, surface series and bar series.


Member Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void CChartXYSerie::AddPoints (double *  pX,
double *  pY,
unsigned  Count 
)
+
+
+ +

+Adds an array of points to the series. +

+Points which were already present in the series are kept.

Parameters:
+ + + + +
pX Array of X values for the points
pY Array of Y values for the points
Count Size of each of both arrays (number of points to add)
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void CChartXYSerie::GetBezierControlPoints (unsigned  uFirst,
unsigned  uLast,
SChartXYPoint *&  pKnots,
SChartXYPoint *&  pFirstControlPoints,
SChartXYPoint *&  pSecondControlPoints 
) const [protected]
+
+
+ +

+Retrieves the control points of a bezier curve fitting the points stored in the array. +

+

Parameters:
+ + + + + + +
uFirst The index of the first point of the bezier curve
uLast The index of the last point of the bezier curve
pKnots This parameter will store the points data
pFirstControlPoints This parameter will store the primary control points of the bezier curve
pSecondControlPoints This parameter will store the secondary control points of the bezier curve
+
+ +
+

+ +

+
+ + + + + + + + + +
void * CChartXYSerie::GetUserData (unsigned  uPointIndex  ) 
+
+
+ +

+Retrieves user data for a specific point. +

+User data can be disabled by adding the flag NO_USER_DATA in the preprocessor definitions. This is usefull when you don't want to have an additional pointer stored for each points in your series. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void CChartXYSerie::SetPoints (double *  pX,
double *  pY,
unsigned  Count 
)
+
+
+ +

+Sets an array of points to the series. +

+Points which were already present in the series are discarded.

Parameters:
+ + + + +
pX Array of X values for the points
pY Array of Y values for the points
Count Size of each of both arrays (number of points to add)
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartXYSerie::SetUserData (unsigned  uPointIndex,
void *  pData 
)
+
+
+ +

+Sets user data for a specific point. +

+User data can be disabled by adding the flag NO_USER_DATA in the preprocessor definitions. This is usefull when you don't want to have an additional pointer stored for each points in your series. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartXYSerie::SetXPointValue (unsigned  PointIndex,
double  NewVal 
)
+
+
+ +

+Sets the X value of a specific point in the series. +

+The control is refreshed to display the change.

Parameters:
+ + + +
PointIndex The index of the points to change the Y value
NewVal The new X value of the point
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void CChartXYSerie::SetYPointValue (unsigned  PointIndex,
double  NewVal 
)
+
+
+ +

+Sets the Y value of a specific point in the series. +

+The control is refreshed to display the change.

Parameters:
+ + + +
PointIndex The index of the points to change the Y value
NewVal The new Y value of the point
+
+ +
+

+


The documentation for this class was generated from the following files:
    +
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartXYSerie.h
  • E:/Sources Misc/ChartDemo/ChartCtrl/ChartXYSerie.cpp
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/class_c_chart_x_y_serie.png b/ChartDemo/Doc/html/class_c_chart_x_y_serie.png new file mode 100644 index 0000000000000000000000000000000000000000..0cb512175f6dfd66248cec7b552222e7e18dfe29 GIT binary patch literal 1944 zcmcgreKgZ+9RDGaNcU80dJ%ddZCp}P3&p$~Oe!@mnPNgw%G-vT^y;@-_ZC};6}pkq zyiG;+OC~R|Fj+#($h8cy*;?i<_c-^Sd;hxU-gBRGp6ByF@ICJP(K9nMN;)$G(dmKLm27rH5R_0oBT!yd zqW5C<0rrEu5CG6Hb9LOcKmN{0W<+HFHtmbYmeM}{6low<1y=`h90HSjW;8bqH)6IH z-ao%+$7lJ{I%!7k8aJRApsCZLNCqz;!nx?3%Q)@*r``)9RuEKM|Q$`~Zzn2ANs|U8IGD20brGT#0z@#)lj)>s*aEARj5G@#|9|ght-`=Z zJ#nn?EkJ~%Ot1Ts;d-StW}+{W^ovwsI`zVoo16KGB%aMWO{Ip?nt;}=ZeAVKo2<&u zMk};YHGNl_Rx%#qU2XTZRpd(I@*^i2xCf~CdSRB%eEpzmKE7VU>-$;Go#Z#LBDzan zLP74>H#Z)e54fI*D)Xq$-f$X5$UU7OQ6wVz_*?wC3K4E`bi7!W(D));Pkb|mqoGEz z*zD9@a#`Oy;}!?($|**cTV0S%WEb>%lfBxZIP33&{5Qo(I7>y~+&E-ucphPVH|Z?g z{zo(MF&#(m)gCH?;Z`6W%qgK&E)(jOgP;}8An0Gy35{hkxuJq^yqvX-FAtI{~GcCR*ZNphKVjBRSmq*n@DbEzokmAhipnR?GnXNid1E^Rqazt zoDUxJOkZWIe>&6o1;I-^BgYCBOhIn3{z*16NI z2igkk3ro?FcauLIxn;UZmsT?5d$Th~B73^w6nA$BB7of}=F-lX4l&psl}&waU9p9i znnh$b%IBOw@f>k-JqGnM+x*M!1l*$mc9#{g47a%*))C*_-rqsJb+T0=7;-k?3 z!l}=nF}~W5w^d=nK@P@mK;wvEA?Sp&e}cPjSIq}3`S6AzGJ8u;coEemG4?@i zUIh%Fz-@wyuCWVJ(L`=${0IFQ)1ex;xRW3AAn9}#UFc;^U;fN_;MKFP2f4}KCiKud zPc~5&ZJ8#tP)!VVx;uHMQ`_)Q;rQCTDSo?Qm<`p|T|HA;$?G3@C4ZN5al6y%ofT4% zQ`QMt_tkZOSl|o9-w0)+7$%Dl4Qk+nvGHEYH+{jaHL{&9Olj+7Ewn=8O^rcCnT9R| OD3>c5<5;*m@Z4`W<9#Op literal 0 HcmV?d00001 diff --git a/ChartDemo/Doc/html/classes.html b/ChartDemo/Doc/html/classes.html new file mode 100644 index 0000000..6f6c2d1 --- /dev/null +++ b/ChartDemo/Doc/html/classes.html @@ -0,0 +1,36 @@ + + +ChartDemo: Alphabetical List + + + + + + +
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/deprecated.html b/ChartDemo/Doc/html/deprecated.html new file mode 100644 index 0000000..8a4bbb8 --- /dev/null +++ b/ChartDemo/Doc/html/deprecated.html @@ -0,0 +1,33 @@ + + +ChartDemo: Deprecated List + + + + + +
+

Deprecated List

+
Member CChartAxis::IsAutomatic () const
+
You should use the GetAutomaticType instead.
+
+

+

+
Member CChartAxis::SetAutomatic (bool bAutomatic)
+
You should use the SetAutomaticType instead.
+
+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/doxygen.css b/ChartDemo/Doc/html/doxygen.css new file mode 100644 index 0000000..3767dc9 --- /dev/null +++ b/ChartDemo/Doc/html/doxygen.css @@ -0,0 +1,441 @@ +body, table, div, p, dl { + font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; + font-size: 12px; +} + +/* @group Heading Levels */ + +h1 { + text-align: center; + font-size: 150%; +} + +h2 { + font-size: 120%; +} + +h3 { + font-size: 100%; +} + +/* @end */ + +caption { + font-weight: bold; +} + +div.qindex, div.navtab{ + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #153788; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #1b77c5; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #6666cc; + color: #ffffff; + border: 1px double #9295C2; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code { +} + +a.codeRef { +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +.fragment { + font-family: monospace, fixed; + font-size: 105%; +} + +pre.fragment { + border: 1px solid #CCCCCC; + background-color: #f5f5f5; + padding: 4px 6px; + margin: 4px 8px 4px 2px; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background: white; + color: black; + margin-right: 20px; + margin-left: 20px; +} + +td.indexkey { + background-color: #e8eef2; + font-weight: bold; + border: 1px solid #CCCCCC; + margin: 2px 0px 2px 0; + padding: 2px 10px; +} + +td.indexvalue { + background-color: #e8eef2; + border: 1px solid #CCCCCC; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #f0f0f0; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +/* @end */ + +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #84b0c7; +} + +th.dirtab { + background: #e8eef2; + font-weight: bold; +} + +hr { + height: 0; + border: none; + border-top: 1px solid #666; +} + +/* @group Member Descriptions */ + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #FAFAFA; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memItemLeft, .memItemRight, .memTemplParams { + border-top: 1px solid #ccc; +} + +.memTemplParams { + color: #606060; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #606060; + font-weight: normal; + margin-left: 3px; +} + +.memnav { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.memitem { + padding: 0; +} + +.memname { + white-space: nowrap; + font-weight: bold; +} + +.memproto, .memdoc { + border: 1px solid #84b0c7; +} + +.memproto { + padding: 0; + background-color: #d5e1e8; + font-weight: bold; + -webkit-border-top-left-radius: 8px; + -webkit-border-top-right-radius: 8px; + -moz-border-radius-topleft: 8px; + -moz-border-radius-topright: 8px; +} + +.memdoc { + padding: 2px 5px; + background-color: #eef3f5; + border-top-width: 0; + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + -moz-border-radius-bottomleft: 8px; + -moz-border-radius-bottomright: 8px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} + +/* @end */ + +/* @group Directory (tree) */ + +/* for the tree view */ + +.ftvtree { + font-family: sans-serif; + margin: 0.5em; +} + +/* these are for tree view when used as main index */ + +.directory { + font-size: 9pt; + font-weight: bold; +} + +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* +The following two styles can be used to replace the root node title +with an image of your choice. Simply uncomment the next two styles, +specify the name of your image and be sure to set 'height' to the +proper pixel height of your image. +*/ + +/* +.directory h3.swap { + height: 61px; + background-repeat: no-repeat; + background-image: url("yourimage.gif"); +} +.directory h3.swap span { + display: none; +} +*/ + +.directory > h3 { + margin-top: 0; +} + +.directory p { + margin: 0px; + white-space: nowrap; +} + +.directory div { + display: none; + margin: 0px; +} + +.directory img { + vertical-align: -30%; +} + +/* these are for tree view when not used as main index */ + +.directory-alt { + font-size: 100%; + font-weight: bold; +} + +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +.directory-alt > h3 { + margin-top: 0; +} + +.directory-alt p { + margin: 0px; + white-space: nowrap; +} + +.directory-alt div { + display: none; + margin: 0px; +} + +.directory-alt img { + vertical-align: -30%; +} + +/* @end */ + +address { + font-style: normal; + color: #333; +} diff --git a/ChartDemo/Doc/html/doxygen.png b/ChartDemo/Doc/html/doxygen.png new file mode 100644 index 0000000000000000000000000000000000000000..f0a274bbaffdd67f6d784c894d9cf28729db0e14 GIT binary patch literal 1281 zcmaJ>ZA?>F7(Vx-ms?uoS`b@hdRtpo6o^%HU>M$hfGrBvQnk$LE?p^P!kn&ikhyq! zX~V@&tPF5Qt@V?oTL96Bi%aRiwbe1)9DWQI#?)=HxS7QSw`J`5fAJ*eJbB;uNuKA& zdERDo*{Y<(If(#(B$Lr#;nB(8Y#ia=ZCeW?JfPLuQY`=@cW$k}Rivq|vbxGrRq1Tl9;+(gNt?}UtVKM2`T5t1jLzuL@0UIs`S#vlhl4)^ zLgSYrPj@$+`|j?eSbXTmiHGkWxV8V}BzNR?pl9k_s4pDu9vd5a_UzZEPk)}Ad{AV_ zzddrjrh4=Imr`E06;LY{)YYt?o}L~H@7C}F^WB!Ra=v`Q0bj{>5&$66CWF>mf6vjP z2N>RRY6ZYa=K`76>+|_)Xdwko+7wv}7cN|btOhWb(*{sta~6b?S8Omrxw}!4`NhGr zZVpNqpu1@BE`QGWNTpEpcJVW5izu~2B^GlM?1(OPg)zwW;QcP@Ltcclm>XbJL9C|j z=9!2?ua=uIlf0%AndzHsRC}IyTL$EhAee(fdKB`?27KeS^2M8M_7b~PiCFO&r5LC7 z7gl1*a<8;SjNaw#h=843_AV9iZbWQOAp5YOC^&_F*9K0> zB|6%IDb?aM#3viTxkLU4aXg&@+CkNTOnQ1iMP*^?b|^lJy$4C)Zk4isV!|RZ*XhXh zw8q3$=*0LeGC!XI_Wc?dkT~3+*Gu%%yIqP+Wr3H$=&ROMQU6q}Ag^P~>c5vAEO;a- z_dK-3PPeKar%)6$j~vI2#*-YH!1h6HYVtwCX5_wM`iF#UKz&&@9Oo5w3%XGYrX zW>dY~)SG-((Yim%`InwgTvyRC?e=Wh^8KCao!R6Eg&TpVWUY1sN~4G}V?nFnEGo-; zHZ_$eW9-GnC%^WS9b z@p;-$oH#MtC0v>Q$HX%4^JdFdO$0cbv-W)Q TtK}Eh@>>I#ipmV1>S*>q-hkC} literal 0 HcmV?d00001 diff --git a/ChartDemo/Doc/html/files.html b/ChartDemo/Doc/html/files.html new file mode 100644 index 0000000..b32d3ce --- /dev/null +++ b/ChartDemo/Doc/html/files.html @@ -0,0 +1,62 @@ + + +ChartDemo: File Index + + + + + +
+

File List

Here is a list of all documented files with brief descriptions: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
E:/Sources Misc/ChartDemo/ChartCtrl/ChartAxis.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartAxisLabel.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartBalloonLabel.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartBarSerie.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartCandlestickSerie.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartCrossHairCursor.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartCtrl.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartCursor.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartDateTimeAxis.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartDragLineCursor.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartFont.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartGanttSerie.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartGradient.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartGrid.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartLabel.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartLegend.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartLineSerie.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartLogarithmicAxis.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartMouseListener.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartPointsArray.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartPointsSerie.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartScrollBar.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartSerie.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartSerieBase.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartSeriesMouseListener.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartStandardAxis.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartString.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartSurfaceSerie.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartTitle.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/ChartXYSerie.h [code]
E:/Sources Misc/ChartDemo/ChartCtrl/PointsOrdering.h [code]
+
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions.html b/ChartDemo/Doc/html/functions.html new file mode 100644 index 0000000..93d8c9f --- /dev/null +++ b/ChartDemo/Doc/html/functions.html @@ -0,0 +1,89 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- a -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x63.html b/ChartDemo/Doc/html/functions_0x63.html new file mode 100644 index 0000000..24f0aea --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x63.html @@ -0,0 +1,147 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- c -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x64.html b/ChartDemo/Doc/html/functions_0x64.html new file mode 100644 index 0000000..95733bb --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x64.html @@ -0,0 +1,96 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- d -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x65.html b/ChartDemo/Doc/html/functions_0x65.html new file mode 100644 index 0000000..579ed42 --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x65.html @@ -0,0 +1,84 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- e -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x66.html b/ChartDemo/Doc/html/functions_0x66.html new file mode 100644 index 0000000..84490d6 --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x66.html @@ -0,0 +1,73 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- f -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x67.html b/ChartDemo/Doc/html/functions_0x67.html new file mode 100644 index 0000000..7560d2b --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x67.html @@ -0,0 +1,248 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- g -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x68.html b/ChartDemo/Doc/html/functions_0x68.html new file mode 100644 index 0000000..365a09e --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x68.html @@ -0,0 +1,71 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- h -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x69.html b/ChartDemo/Doc/html/functions_0x69.html new file mode 100644 index 0000000..38a883c --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x69.html @@ -0,0 +1,96 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- i -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x6c.html b/ChartDemo/Doc/html/functions_0x6c.html new file mode 100644 index 0000000..3e009b3 --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x6c.html @@ -0,0 +1,71 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- l -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x6d.html b/ChartDemo/Doc/html/functions_0x6d.html new file mode 100644 index 0000000..20c250c --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x6d.html @@ -0,0 +1,144 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- m -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x6e.html b/ChartDemo/Doc/html/functions_0x6e.html new file mode 100644 index 0000000..fa99c79 --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x6e.html @@ -0,0 +1,75 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- n -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x6f.html b/ChartDemo/Doc/html/functions_0x6f.html new file mode 100644 index 0000000..adb062b --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x6f.html @@ -0,0 +1,108 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- o -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x70.html b/ChartDemo/Doc/html/functions_0x70.html new file mode 100644 index 0000000..fd142be --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x70.html @@ -0,0 +1,77 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- p -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x72.html b/ChartDemo/Doc/html/functions_0x72.html new file mode 100644 index 0000000..82b797c --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x72.html @@ -0,0 +1,102 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- r -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x73.html b/ChartDemo/Doc/html/functions_0x73.html new file mode 100644 index 0000000..b416200 --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x73.html @@ -0,0 +1,245 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- s -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x74.html b/ChartDemo/Doc/html/functions_0x74.html new file mode 100644 index 0000000..132e8eb --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x74.html @@ -0,0 +1,71 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- t -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x75.html b/ChartDemo/Doc/html/functions_0x75.html new file mode 100644 index 0000000..91991e3 --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x75.html @@ -0,0 +1,79 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- u -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x76.html b/ChartDemo/Doc/html/functions_0x76.html new file mode 100644 index 0000000..ba370dd --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x76.html @@ -0,0 +1,78 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- v -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x78.html b/ChartDemo/Doc/html/functions_0x78.html new file mode 100644 index 0000000..6b09567 --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x78.html @@ -0,0 +1,75 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- x -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x79.html b/ChartDemo/Doc/html/functions_0x79.html new file mode 100644 index 0000000..30d20f0 --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x79.html @@ -0,0 +1,75 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- y -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_0x7e.html b/ChartDemo/Doc/html/functions_0x7e.html new file mode 100644 index 0000000..8168cb4 --- /dev/null +++ b/ChartDemo/Doc/html/functions_0x7e.html @@ -0,0 +1,111 @@ + + +ChartDemo: Class Members + + + + + +
+Here is a list of all documented class members with links to the class documentation for each member: +

+

- ~ -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_enum.html b/ChartDemo/Doc/html/functions_enum.html new file mode 100644 index 0000000..fb3e9dd --- /dev/null +++ b/ChartDemo/Doc/html/functions_enum.html @@ -0,0 +1,58 @@ + + +ChartDemo: Class Members - Enumerations + + + + + +
+  +

+

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_eval.html b/ChartDemo/Doc/html/functions_eval.html new file mode 100644 index 0000000..b2439ea --- /dev/null +++ b/ChartDemo/Doc/html/functions_eval.html @@ -0,0 +1,50 @@ + + +ChartDemo: Class Members - Enumerator + + + + + +
+  +

+

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func.html b/ChartDemo/Doc/html/functions_func.html new file mode 100644 index 0000000..789cc52 --- /dev/null +++ b/ChartDemo/Doc/html/functions_func.html @@ -0,0 +1,84 @@ + + +ChartDemo: Class Members - Functions + + + + + +
+  +

+

- a -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func_0x63.html b/ChartDemo/Doc/html/functions_func_0x63.html new file mode 100644 index 0000000..12ff18d --- /dev/null +++ b/ChartDemo/Doc/html/functions_func_0x63.html @@ -0,0 +1,140 @@ + + +ChartDemo: Class Members - Functions + + + + + +
+  +

+

- c -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func_0x64.html b/ChartDemo/Doc/html/functions_func_0x64.html new file mode 100644 index 0000000..13ae1bd --- /dev/null +++ b/ChartDemo/Doc/html/functions_func_0x64.html @@ -0,0 +1,89 @@ + + +ChartDemo: Class Members - Functions + + + + + + +
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func_0x65.html b/ChartDemo/Doc/html/functions_func_0x65.html new file mode 100644 index 0000000..7885ede --- /dev/null +++ b/ChartDemo/Doc/html/functions_func_0x65.html @@ -0,0 +1,73 @@ + + +ChartDemo: Class Members - Functions + + + + + +
+  +

+

- e -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func_0x67.html b/ChartDemo/Doc/html/functions_func_0x67.html new file mode 100644 index 0000000..6637354 --- /dev/null +++ b/ChartDemo/Doc/html/functions_func_0x67.html @@ -0,0 +1,243 @@ + + +ChartDemo: Class Members - Functions + + + + + +
+  +

+

- g -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func_0x69.html b/ChartDemo/Doc/html/functions_func_0x69.html new file mode 100644 index 0000000..863079d --- /dev/null +++ b/ChartDemo/Doc/html/functions_func_0x69.html @@ -0,0 +1,91 @@ + + +ChartDemo: Class Members - Functions + + + + + +
+  +

+

- i -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func_0x6e.html b/ChartDemo/Doc/html/functions_func_0x6e.html new file mode 100644 index 0000000..6c1cf5b --- /dev/null +++ b/ChartDemo/Doc/html/functions_func_0x6e.html @@ -0,0 +1,68 @@ + + +ChartDemo: Class Members - Functions + + + + + +
+  +

+

- n -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func_0x6f.html b/ChartDemo/Doc/html/functions_func_0x6f.html new file mode 100644 index 0000000..a04d99c --- /dev/null +++ b/ChartDemo/Doc/html/functions_func_0x6f.html @@ -0,0 +1,101 @@ + + +ChartDemo: Class Members - Functions + + + + + +
+  +

+

- o -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func_0x70.html b/ChartDemo/Doc/html/functions_func_0x70.html new file mode 100644 index 0000000..c924a5d --- /dev/null +++ b/ChartDemo/Doc/html/functions_func_0x70.html @@ -0,0 +1,68 @@ + + +ChartDemo: Class Members - Functions + + + + + +
+  +

+

- p -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func_0x72.html b/ChartDemo/Doc/html/functions_func_0x72.html new file mode 100644 index 0000000..f8e22a1 --- /dev/null +++ b/ChartDemo/Doc/html/functions_func_0x72.html @@ -0,0 +1,97 @@ + + +ChartDemo: Class Members - Functions + + + + + +
+  +

+

- r -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func_0x73.html b/ChartDemo/Doc/html/functions_func_0x73.html new file mode 100644 index 0000000..a0ac19c --- /dev/null +++ b/ChartDemo/Doc/html/functions_func_0x73.html @@ -0,0 +1,236 @@ + + +ChartDemo: Class Members - Functions + + + + + +
+  +

+

- s -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func_0x75.html b/ChartDemo/Doc/html/functions_func_0x75.html new file mode 100644 index 0000000..3e6d8ef --- /dev/null +++ b/ChartDemo/Doc/html/functions_func_0x75.html @@ -0,0 +1,74 @@ + + +ChartDemo: Class Members - Functions + + + + + +
+  +

+

- u -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func_0x76.html b/ChartDemo/Doc/html/functions_func_0x76.html new file mode 100644 index 0000000..732cd15 --- /dev/null +++ b/ChartDemo/Doc/html/functions_func_0x76.html @@ -0,0 +1,73 @@ + + +ChartDemo: Class Members - Functions + + + + + +
+  +

+

- v -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func_0x78.html b/ChartDemo/Doc/html/functions_func_0x78.html new file mode 100644 index 0000000..5c931e4 --- /dev/null +++ b/ChartDemo/Doc/html/functions_func_0x78.html @@ -0,0 +1,66 @@ + + +ChartDemo: Class Members - Functions + + + + + +
+  +

+

- x -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func_0x79.html b/ChartDemo/Doc/html/functions_func_0x79.html new file mode 100644 index 0000000..88e6e94 --- /dev/null +++ b/ChartDemo/Doc/html/functions_func_0x79.html @@ -0,0 +1,66 @@ + + +ChartDemo: Class Members - Functions + + + + + +
+  +

+

- y -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_func_0x7e.html b/ChartDemo/Doc/html/functions_func_0x7e.html new file mode 100644 index 0000000..db36be7 --- /dev/null +++ b/ChartDemo/Doc/html/functions_func_0x7e.html @@ -0,0 +1,106 @@ + + +ChartDemo: Class Members - Functions + + + + + +
+  +

+

- ~ -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/functions_vars.html b/ChartDemo/Doc/html/functions_vars.html new file mode 100644 index 0000000..1ddad61 --- /dev/null +++ b/ChartDemo/Doc/html/functions_vars.html @@ -0,0 +1,171 @@ + + +ChartDemo: Class Members - Variables + + + + + +
+  +

+

- c -

+

- e -

+

- h -

+

- l -

+

- m -

+

- o -

+

- p -

+

- s -

+

- x -

+

- y -

+
+
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/hierarchy.html b/ChartDemo/Doc/html/hierarchy.html new file mode 100644 index 0000000..f398392 --- /dev/null +++ b/ChartDemo/Doc/html/hierarchy.html @@ -0,0 +1,95 @@ + + +ChartDemo: Hierarchical Index + + + + + + +
Generated on Sun Jan 17 13:33:10 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/index.html b/ChartDemo/Doc/html/index.html new file mode 100644 index 0000000..b930fd8 --- /dev/null +++ b/ChartDemo/Doc/html/index.html @@ -0,0 +1,26 @@ + + +ChartDemo: Main Page + + + + + +
+

ChartDemo Documentation

+

+

3.0.1

+
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/pages.html b/ChartDemo/Doc/html/pages.html new file mode 100644 index 0000000..1fa3899 --- /dev/null +++ b/ChartDemo/Doc/html/pages.html @@ -0,0 +1,28 @@ + + +ChartDemo: Page Index + + + + + +
+

Related Pages

Here is a list of all related documentation pages: +
+
Generated on Sun Jan 17 13:33:09 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/resource_8h-source.html b/ChartDemo/Doc/html/resource_8h-source.html new file mode 100644 index 0000000..20bb331 --- /dev/null +++ b/ChartDemo/Doc/html/resource_8h-source.html @@ -0,0 +1,103 @@ + + +ChartDemo: E:/Sources Misc/ChartDemo/resource.h Source File + + + + + +
Generated on Sat Mar 7 11:33:24 2009 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/struct_c_chart_points_array_1_1_s_chart_point-members.html b/ChartDemo/Doc/html/struct_c_chart_points_array_1_1_s_chart_point-members.html new file mode 100644 index 0000000..2c2654b --- /dev/null +++ b/ChartDemo/Doc/html/struct_c_chart_points_array_1_1_s_chart_point-members.html @@ -0,0 +1,33 @@ + + +ChartDemo: Member List + + + + + +
+

CChartPointsArray::CChartPointsArray::SChartPoint Member List

This is the complete list of members for CChartPointsArray::CChartPointsArray::SChartPoint, including all inherited members.

+ + +
XCChartPointsArray::CChartPointsArray::SChartPoint
YCChartPointsArray::CChartPointsArray::SChartPoint

+
Generated on Sun Mar 8 17:21:19 2009 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/struct_c_chart_points_array_1_1_s_chart_point.html b/ChartDemo/Doc/html/struct_c_chart_points_array_1_1_s_chart_point.html new file mode 100644 index 0000000..cd783b9 --- /dev/null +++ b/ChartDemo/Doc/html/struct_c_chart_points_array_1_1_s_chart_point.html @@ -0,0 +1,54 @@ + + +ChartDemo: CChartPointsArray::CChartPointsArray::SChartPoint Struct Reference + + + + + +
+

CChartPointsArray::CChartPointsArray::SChartPoint Struct Reference

Structure containing a point data. +More... +

+#include <ChartPointsArray.h> +

+ +

+List of all members. + + + + + + + + +

Public Attributes

+double X
 The point X value.
+double Y
 The point Y value.
+


Detailed Description

+Structure containing a point data.
The documentation for this struct was generated from the following file: +
+
Generated on Sun Mar 8 17:21:19 2009 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/struct_s_chart_candlestick_point-members.html b/ChartDemo/Doc/html/struct_s_chart_candlestick_point-members.html new file mode 100644 index 0000000..4da7640 --- /dev/null +++ b/ChartDemo/Doc/html/struct_s_chart_candlestick_point-members.html @@ -0,0 +1,45 @@ + + +ChartDemo: Member List + + + + + +
+

SChartCandlestickPoint Member List

This is the complete list of members for SChartCandlestickPoint, including all inherited members.

+ + + + + + + + + + + + + +
CloseSChartCandlestickPoint
GetX() const SChartCandlestickPoint [inline]
GetXMax() const SChartCandlestickPoint [inline]
GetXMin() const SChartCandlestickPoint [inline]
GetY() const SChartCandlestickPoint [inline]
GetYMax() const SChartCandlestickPoint [inline]
GetYMin() const SChartCandlestickPoint [inline]
HighSChartCandlestickPoint
LowSChartCandlestickPoint
OpenSChartCandlestickPoint
SChartCandlestickPoint() (defined in SChartCandlestickPoint)SChartCandlestickPoint [inline]
SChartCandlestickPoint(double XValue, double LowVal, double HighVal, double OpenVal, double CloseVal) (defined in SChartCandlestickPoint)SChartCandlestickPoint [inline]
XValSChartCandlestickPoint

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/struct_s_chart_candlestick_point.html b/ChartDemo/Doc/html/struct_s_chart_candlestick_point.html new file mode 100644 index 0000000..64f592f --- /dev/null +++ b/ChartDemo/Doc/html/struct_s_chart_candlestick_point.html @@ -0,0 +1,93 @@ + + +ChartDemo: SChartCandlestickPoint Struct Reference + + + + + +
+

SChartCandlestickPoint Struct Reference

Point structure used as template parameter for candlestick series. +More... +

+#include <ChartCandlestickSerie.h> +

+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

SChartCandlestickPoint (double XValue, double LowVal, double HighVal, double OpenVal, double CloseVal)
+double GetX () const
 Returns the X value of the point.
+double GetY () const
 Returns the Y value of the point, which is the average between low and high.
+double GetXMin () const
 Returns the minimum X value of the point.
+double GetXMax () const
 Returns the maximum X value of the point.
+double GetYMin () const
 Returns the minimum Y value of the point (the low value).
+double GetYMax () const
 Returns the maximum Y value of the point (the high value).

Public Attributes

+double XVal
 The X value of the point (usually, a time).
+double Low
 The low market price.
+double High
 The high market price.
+double Open
 The open market price.
+double Close
 The close market price.
+


Detailed Description

+Point structure used as template parameter for candlestick series.
The documentation for this struct was generated from the following file: +
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/struct_s_chart_gantt_point-members.html b/ChartDemo/Doc/html/struct_s_chart_gantt_point-members.html new file mode 100644 index 0000000..cd37d72 --- /dev/null +++ b/ChartDemo/Doc/html/struct_s_chart_gantt_point-members.html @@ -0,0 +1,43 @@ + + +ChartDemo: Member List + + + + + +
+

SChartGanttPoint Member List

This is the complete list of members for SChartGanttPoint, including all inherited members.

+ + + + + + + + + + + +
EndTimeSChartGanttPoint
GetX() const SChartGanttPoint [inline]
GetXMax() const SChartGanttPoint [inline]
GetXMin() const SChartGanttPoint [inline]
GetY() const SChartGanttPoint [inline]
GetYMax() const SChartGanttPoint [inline]
GetYMin() const SChartGanttPoint [inline]
SChartGanttPoint()SChartGanttPoint [inline]
SChartGanttPoint(double Start, double End, double YVal)SChartGanttPoint [inline]
StartTimeSChartGanttPoint
YValueSChartGanttPoint

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/struct_s_chart_gantt_point.html b/ChartDemo/Doc/html/struct_s_chart_gantt_point.html new file mode 100644 index 0000000..d77032b --- /dev/null +++ b/ChartDemo/Doc/html/struct_s_chart_gantt_point.html @@ -0,0 +1,90 @@ + + +ChartDemo: SChartGanttPoint Struct Reference + + + + + +
+

SChartGanttPoint Struct Reference

Point structure used as template parameter for gantt series. +More... +

+#include <ChartGanttSerie.h> +

+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

SChartGanttPoint ()
 Default constructor.
SChartGanttPoint (double Start, double End, double YVal)
 Construct a new gantt point with the specifed values.
+double GetX () const
 Returns the X value of the point, which is the average between start time and end time.
+double GetY () const
 Returns the Y value.
+double GetXMin () const
 Returns the start time.
+double GetXMax () const
 Returns the end time.
+double GetYMin () const
 Returns the Y value.
+double GetYMax () const
 Returns the Y value.

Public Attributes

+double StartTime
 The start time of the gantt point.
+double EndTime
 The end time of the gantt point.
+double YValue
 The Y value of the gantt point.
+


Detailed Description

+Point structure used as template parameter for gantt series.
The documentation for this struct was generated from the following file: +
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/struct_s_chart_x_y_point-members.html b/ChartDemo/Doc/html/struct_s_chart_x_y_point-members.html new file mode 100644 index 0000000..e2acbe7 --- /dev/null +++ b/ChartDemo/Doc/html/struct_s_chart_x_y_point-members.html @@ -0,0 +1,43 @@ + + +ChartDemo: Member List + + + + + +
+

SChartXYPoint Member List

This is the complete list of members for SChartXYPoint, including all inherited members.

+ + + + + + + + + + + +
GetX() const (defined in SChartXYPoint)SChartXYPoint [inline]
GetXMax() const (defined in SChartXYPoint)SChartXYPoint [inline]
GetXMin() const (defined in SChartXYPoint)SChartXYPoint [inline]
GetY() const (defined in SChartXYPoint)SChartXYPoint [inline]
GetYMax() const (defined in SChartXYPoint)SChartXYPoint [inline]
GetYMin() const (defined in SChartXYPoint)SChartXYPoint [inline]
pUserDataSChartXYPoint
SChartXYPoint() (defined in SChartXYPoint)SChartXYPoint [inline]
SChartXYPoint(double XVal, double YVal) (defined in SChartXYPoint)SChartXYPoint [inline]
XSChartXYPoint
YSChartXYPoint

+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/struct_s_chart_x_y_point.html b/ChartDemo/Doc/html/struct_s_chart_x_y_point.html new file mode 100644 index 0000000..b1f6977 --- /dev/null +++ b/ChartDemo/Doc/html/struct_s_chart_x_y_point.html @@ -0,0 +1,79 @@ + + +ChartDemo: SChartXYPoint Struct Reference + + + + + +
+

SChartXYPoint Struct Reference

Structure containing a point data with X and Y values. +More... +

+#include <ChartXYSerie.h> +

+ +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

SChartXYPoint (double XVal, double YVal)
+double GetX () const
+double GetY () const
+double GetXMin () const
+double GetXMax () const
+double GetYMin () const
+double GetYMax () const

Public Attributes

+double X
 The point X value.
+double Y
 The point Y value.
+void * pUserData
 Optional user data.
+


Detailed Description

+Structure containing a point data with X and Y values.
The documentation for this struct was generated from the following file: +
+
Generated on Sun Jan 17 13:33:11 2010 for ChartDemo by  + +doxygen 1.5.8
+ + diff --git a/ChartDemo/Doc/html/tab_b.gif b/ChartDemo/Doc/html/tab_b.gif new file mode 100644 index 0000000000000000000000000000000000000000..0d623483ffdf5f9f96900108042a7ab0643fe2a3 GIT binary patch literal 35 ncmZ?wbhEHbWMp7uXkcJy*>IeJfk6j|fqX^=1|}vKMh0sDa2W*H literal 0 HcmV?d00001 diff --git a/ChartDemo/Doc/html/tab_l.gif b/ChartDemo/Doc/html/tab_l.gif new file mode 100644 index 0000000000000000000000000000000000000000..9b1e6337c9299a700401a2a78a2c6ffced475216 GIT binary patch literal 706 zcmZ?wbhEHbZT`}F1e&(Gg}Y(8=I;HA5#Z$3JI=gGB)FQ#odI(O&E^@q;x zK6mr*m3xOS-#u~t!I@i+u0DKm^U160k6t`|^WpV}&n+8{U%dD9&a>B#U%!9-@yol< zU%&tQ{rk_K|NsC0`}dE5ET99@1@a36+kb~?0UJ*yc&I3X_m z!ND^5$O7$#8OFRuDhG}!?8z?cdZK&!`PWjdR;Aj^wZ` zeK{IEYHBJ)6K8VIp1`BVt++swf6j+=L{p1*nO(VhE`pFexG@5$|>uaCcd z`0m=9m+yak{QmXN#Sc$^{$X9h9&q2jiKAI|&T)a;PPx2K9p`YIdw8HtR5k2Q$2-O2 z*;3y{MQ-RnJTgJfI&R5|O)AHxDf_00XbPvDZPy4t=hHd)nfLPvms&O`Ok(sD()5v$ z5U@&h;a=#xbxVbo2~X&Xj0Ie(f{v>vERH+qC+nTG=B8Nca=wU-O$?1&vUgV~9=!H; zx>3p9Yn%*<>t~sk+&0xfyS8RsPfYBd<~wWK%j-LmpU>O7yX^h#UCp1x-p#i7@bE;py8XI6 zmY<)m>~)W~yIWcMVoiPg{duuf<*)9qZ9l$m*Ph&W&$jlv*Vpa+{pH@n=IQ$L?0$ax ec60Ul|8o2P|NVbd{6P)#weSbE3}s?04AuZvx_~SI literal 0 HcmV?d00001 diff --git a/ChartDemo/Doc/html/tab_r.gif b/ChartDemo/Doc/html/tab_r.gif new file mode 100644 index 0000000000000000000000000000000000000000..ce9dd9f533cb5486d6941844f442b59d4a9e9175 GIT binary patch literal 2585 zcmbV}`9Bkk1ILFF--w5zJc=ZZT(zjE=;2|_S)Qm~rCWz1Pc)KPl;jv%A#&v2*x}yc zmf2~Jm~&=xjJY?PqwIN}f8qQ2{r$uH{c*nJbmr{cR5??*egHrs-B=MzCF`3%e{FAW z{oL5xTHn~5TM{jaB;@|_Ue5F&Zb@p(kMyG{*;gWDg zyeL|eZf7Qd8=#bXzSiR{yzRgLSj-fJS8>lBjVHN z^o-0eS=nE6a`W;LChBs=`+QAJP~{b93>H^eRb5kCSC1zUNezun%`L5M?RDzv#%jk7 zYVRX=vATPD`+oEfum^{RM@GjuP?-r=yh0!p;Vx^T9G7~`7%5ydH%70=jyJ;;`d;hv92x3R=z{xp+Lg2!*@OK*K15-t&okoPtSED)h&$RLxdbA zseWm^C3d%-yRNi-ryk^!ek+C`n&~cd$#ZWct_cUL{l~i+Nzx^5d!n94(>bW-iL~Rl z&8r)?q|1DIo=0=judQ{FaGcfLERz8gfn3-Qt<2lksh{mzpT}DXxUuR^z=^key&q4! z+wWI45vL0k$R^(F#{qfqhUsN@WA+w-V?LPH33!Q?WFSB3)WBojE@hK41Nb?KfS+Qo zXgrzfsP$wr4Qzy*{OD>uJBjdgGM@VMml5)2f~_}lD*YyOb}Hjeobhz#4c`w(l^>KK zr?Ud;W~Z}*w;%hZ|2^p^+f06gJDJQD zeIhGADbDmm&6arh(q>EZ<7mjzg7l|z$hRL8=1>)Nv=S7CY$B}iYJ&*T_-T_OG*L1q ztZ3Lana33?y3AKnyq^YCF|4x%Rb5WU&2qcl{TFKey%QJeMxn^SdT!hZ5+0i1zeusiYVp-phBl7b5+Px-X&LhByq z0F&<;K0l2+v>qiHlXb#$jXMv$uK-dEGE9L~qtdU(XeRXmvu*K2Q&6!fD**JxYP4b4BR7FdJ$Qx9G9`J%-_X!a#LGpp3g9)VWytGCa;7`S1_e8F~!R+aSJ zOF17p2`H?2kPs8Q`_;U}+D%3p zs2-0BTqFwpUoBk`?P;iPQ(IbEA|JmMx!P&YYG|R@S=5Mnw;-?A6rEEVyV%d7{iU4a zNk`i!%F(Ykpm`}#oH;BjY->@b8vQedv;pza2FL&*6ufjd+*3Ute&>kes~TU?^KkojsTh(o~(3tk1Y6>4(yn( z#U*ID9@eg-beKo1B;HXe+}{Z%n@7m0+yxivuqk9~;!1LGQlah)xYK4>wgL}l6dsaN zIxlRlq`*`j9PG4*0hD6YV_b_2w5b#)o7J?`q#{GjvvKlD`T*dWcZx<-s(ZvLB44E# z=!|sw!?)@%y$oRNL#25WS3lzdii}TuQ3?CLnvQ1_n};2sT_;Y;#d3=+-(O% zMN$>O!3;ke(UuLR%h_&)N zs^!-@A>QR}4yB1bPp`9S19ikTbZ~O{&FF-yHK{En;mmShDUIEw03`j(DBIsM}Rjki2J#SQa3gFZTKBPDeIiLt9Z z%bL3(B@Qw%(B`wSMS~dPh$=R`(}lBoFXKy(s|*{#ru$wjsBc_O#zxNk9w+UUHmx(U zmJ8+M+ndtnZ<7|VU9Mbt61zpo9T&3%Wx&XII=#QJxjR`CZf22ac3d51Z?GD%LEe_&*t46Qf;4`bZ7p2K(Ab5>GfT^}4! zBT&HZD`^PEgWoI&{~o-ID0F?O`75sm(87x%A{(}Ch1)QlzdJ)1B-eqe5a(weg0`4lQIf1evjvbBY50DVbzO7CLf|vP z2#0(U-|jZ`H{y5N^o7%iK6H>_HEGN->U6^!)1{XpJV!!4(Ig7wzZQ*9WYF4X1rG0x z=1uA@i`rIAciubDC{;~b(|&|A@xkjRP5aRcvRU9tvIm}jDB6J eQ0-6-y)mpwdT=ayS0tBxKDA*~;EWmo literal 0 HcmV?d00001 diff --git a/ChartDemo/Doc/html/tabs.css b/ChartDemo/Doc/html/tabs.css new file mode 100644 index 0000000..ab02c62 --- /dev/null +++ b/ChartDemo/Doc/html/tabs.css @@ -0,0 +1,105 @@ +/* tabs styles, based on http://www.alistapart.com/articles/slidingdoors */ + +DIV.tabs +{ + float : left; + width : 100%; + background : url("tab_b.gif") repeat-x bottom; + margin-bottom : 4px; +} + +DIV.tabs UL +{ + margin : 0px; + padding-left : 10px; + list-style : none; +} + +DIV.tabs LI, DIV.tabs FORM +{ + display : inline; + margin : 0px; + padding : 0px; +} + +DIV.tabs FORM +{ + float : right; +} + +DIV.tabs A +{ + float : left; + background : url("tab_r.gif") no-repeat right top; + border-bottom : 1px solid #84B0C7; + font-size : 80%; + font-weight : bold; + text-decoration : none; +} + +DIV.tabs A:hover +{ + background-position: 100% -150px; +} + +DIV.tabs A:link, DIV.tabs A:visited, +DIV.tabs A:active, DIV.tabs A:hover +{ + color: #1A419D; +} + +DIV.tabs SPAN +{ + float : left; + display : block; + background : url("tab_l.gif") no-repeat left top; + padding : 5px 9px; + white-space : nowrap; +} + +DIV.tabs INPUT +{ + float : right; + display : inline; + font-size : 1em; +} + +DIV.tabs TD +{ + font-size : 80%; + font-weight : bold; + text-decoration : none; +} + + + +/* Commented Backslash Hack hides rule from IE5-Mac \*/ +DIV.tabs SPAN {float : none;} +/* End IE5-Mac hack */ + +DIV.tabs A:hover SPAN +{ + background-position: 0% -150px; +} + +DIV.tabs LI.current A +{ + background-position: 100% -150px; + border-width : 0px; +} + +DIV.tabs LI.current SPAN +{ + background-position: 0% -150px; + padding-bottom : 6px; +} + +DIV.navpath +{ + background : none; + border : none; + border-bottom : 1px solid #84B0C7; + text-align : center; + margin : 2px; + padding : 2px; +} diff --git a/ChartDemo/LinePropDialog.cpp b/ChartDemo/LinePropDialog.cpp new file mode 100644 index 0000000..8092332 --- /dev/null +++ b/ChartDemo/LinePropDialog.cpp @@ -0,0 +1,63 @@ +// LinePropDialog.cpp : implementation file +// + +#include "stdafx.h" +#include "chartdemo.h" +#include "LinePropDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CLinePropDialog dialog + + +CLinePropDialog::CLinePropDialog(CWnd* pParent /*=NULL*/) + : CDialog(CLinePropDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CLinePropDialog) + m_iLineWidth = 0; + m_iPenStyle = -1; + //}}AFX_DATA_INIT +} + + +void CLinePropDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CLinePropDialog) + DDX_Text(pDX, IDC_LINEWIDTH_EDIT, m_iLineWidth); + DDX_CBIndex(pDX, IDC_PENSTYLE_COMBO, m_iPenStyle); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CLinePropDialog, CDialog) + //{{AFX_MSG_MAP(CLinePropDialog) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CLinePropDialog message handlers + +BOOL CLinePropDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_iLineWidth = 1; + m_iPenStyle = 0; + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CLinePropDialog::OnOK() +{ + UpdateData(TRUE); + + CDialog::OnOK(); +} diff --git a/ChartDemo/LinePropDialog.h b/ChartDemo/LinePropDialog.h new file mode 100644 index 0000000..38c7385 --- /dev/null +++ b/ChartDemo/LinePropDialog.h @@ -0,0 +1,48 @@ +#if !defined(AFX_LINEPROPDIALOG_H__8B4BF925_24C6_41B2_8BEB_98E6A52322A8__INCLUDED_) +#define AFX_LINEPROPDIALOG_H__8B4BF925_24C6_41B2_8BEB_98E6A52322A8__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// LinePropDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CLinePropDialog dialog + +class CLinePropDialog : public CDialog +{ +// Construction +public: + CLinePropDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CLinePropDialog) + enum { IDD = IDD_LINEPROP_DLG }; + int m_iLineWidth; + int m_iPenStyle; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLinePropDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CLinePropDialog) + virtual BOOL OnInitDialog(); + virtual void OnOK(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_LINEPROPDIALOG_H__8B4BF925_24C6_41B2_8BEB_98E6A52322A8__INCLUDED_) diff --git a/ChartDemo/PointsPropDialog.cpp b/ChartDemo/PointsPropDialog.cpp new file mode 100644 index 0000000..989348a --- /dev/null +++ b/ChartDemo/PointsPropDialog.cpp @@ -0,0 +1,73 @@ +// PointsPropDialog.cpp : implementation file +// + +#include "stdafx.h" +#include "chartdemo.h" +#include "PointsPropDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CPointsPropDialog dialog + + +CPointsPropDialog::CPointsPropDialog(CWnd* pParent /*=NULL*/) + : CDialog(CPointsPropDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CPointsPropDialog) + m_iPointsHeight = 0; + m_iPointsWidth = 0; + m_iPointsType = -1; + //}}AFX_DATA_INIT +} + + +void CPointsPropDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CPointsPropDialog) + DDX_Text(pDX, IDC_POINTHEIGHT_EDIT, m_iPointsHeight); + DDV_MinMaxInt(pDX, m_iPointsHeight, 0, 20); + DDX_Text(pDX, IDC_POINTWIDTH_EDIT, m_iPointsWidth); + DDV_MinMaxInt(pDX, m_iPointsWidth, 0, 20); + DDX_CBIndex(pDX, IDC_POINTTYPE_COMBO, m_iPointsType); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CPointsPropDialog, CDialog) + //{{AFX_MSG_MAP(CPointsPropDialog) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CPointsPropDialog message handlers + +void CPointsPropDialog::OnCancel() +{ + +} + +void CPointsPropDialog::OnOK() +{ + UpdateData(TRUE); + + CDialog::OnOK(); +} + +BOOL CPointsPropDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_iPointsWidth = m_iPointsHeight = 5; + m_iPointsType = 0; + UpdateData(FALSE); + + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} diff --git a/ChartDemo/PointsPropDialog.h b/ChartDemo/PointsPropDialog.h new file mode 100644 index 0000000..0d96c9b --- /dev/null +++ b/ChartDemo/PointsPropDialog.h @@ -0,0 +1,50 @@ +#if !defined(AFX_POINTSPROPDIALOG_H__F83DDA1D_53B7_457E_B354_02462E1C8568__INCLUDED_) +#define AFX_POINTSPROPDIALOG_H__F83DDA1D_53B7_457E_B354_02462E1C8568__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// PointsPropDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CPointsPropDialog dialog + +class CPointsPropDialog : public CDialog +{ +// Construction +public: + CPointsPropDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CPointsPropDialog) + enum { IDD = IDD_POINTPROP_DLG }; + int m_iPointsHeight; + int m_iPointsWidth; + int m_iPointsType; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPointsPropDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CPointsPropDialog) + virtual void OnCancel(); + virtual void OnOK(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_POINTSPROPDIALOG_H__F83DDA1D_53B7_457E_B354_02462E1C8568__INCLUDED_) diff --git a/ChartDemo/SeriesPropDlg.cpp b/ChartDemo/SeriesPropDlg.cpp new file mode 100644 index 0000000..4a6f586 --- /dev/null +++ b/ChartDemo/SeriesPropDlg.cpp @@ -0,0 +1,204 @@ +// SeriesPropDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "ChartDemo.h" +#include "SeriesPropDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CSeriesPropDlg dialog + + +CSeriesPropDlg::CSeriesPropDlg(CWnd* pParent /*=NULL*/) + : CDialog(CSeriesPropDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CSeriesPropDlg) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT + m_iHorizAxis = m_iVertAxis = 0; + m_iSeriesType = 1; + //m_SeriesColour = 0; + m_iDataType = 0; + m_fMaxXValue = m_fMinXValue = 0.0; + m_iPointsNumber = 0; + + m_iRandMinVal = m_iRandMaxVal = 0; + m_fSineAmplitude = m_fSinePeriod = 0; + m_fLineSlope = m_fLineOffset = 0; + m_SeriesColour = 0x002068ff; + m_ColourSelect.SetColour(m_SeriesColour); +} + + +void CSeriesPropDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CSeriesPropDlg) + DDX_Control(pDX, IDC_VERTICALAXIS_COMBO, m_VertAxisCombo); + DDX_Control(pDX, IDC_HORIZONTALAXIS_COMBO, m_HorizAxisCombo); + DDX_Control(pDX, IDC_SERIESCOLOUR_BTN, m_ColourSelect); + DDX_Control(pDX, IDC_SERIESTYPE_COMBO, m_SeriesTypeCombo); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CSeriesPropDlg, CDialog) + //{{AFX_MSG_MAP(CSeriesPropDlg) + ON_BN_CLICKED(IDC_LINEDATA_RADIO, OnSelectLineData) + ON_BN_CLICKED(IDC_RANDOMDATA_RADIO, OnSelectRandomData) + ON_BN_CLICKED(IDC_SINEDATA_RADIO, OnSelectSineData) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CSeriesPropDlg message handlers + +void CSeriesPropDlg::OnOK() +{ + TCHAR szName[255]; + GetDlgItem(IDC_SERIESNAME_EDIT)->GetWindowText(szName,254); + m_strSeriesName = szName; + + if (_tcscmp(szName,_T("")) == 0) + { + MessageBox(_T("You must supply a name"),_T("Error")); + return; + } + + m_iSeriesType = m_SeriesTypeCombo.GetCurSel(); + m_SeriesColour = m_ColourSelect.GetColour(); + + TCHAR szBuff[255]; + GetDlgItem(IDC_MAXXVALUE_EDIT)->GetWindowText(szBuff,254); +// m_fMaxXValue = (float)_tstof(szBuff); + m_fMaxXValue = (float)_tcstod(szBuff, NULL); + GetDlgItem(IDC_MINXVALUE_EDIT)->GetWindowText(szBuff,254); +// m_fMinXValue = (float)_tstof(szBuff); + m_fMinXValue = (float)_tcstod(szBuff, NULL); + if (m_fMinXValue > m_fMaxXValue) + { + MessageBox(_T("Max X value should be > Min X value")); + return; + } + + m_iHorizAxis = m_HorizAxisCombo.GetCurSel(); + m_iVertAxis = m_VertAxisCombo.GetCurSel(); + + GetDlgItem(IDC_POINTSNUMBER_EDIT)->GetWindowText(szBuff,254); +#ifdef UNICODE + m_iPointsNumber = _wtoi(szBuff); +#else + m_iPointsNumber = atoi(szBuff); +#endif + if (m_iPointsNumber < 2) + { + MessageBox(_T("Number of points should be > 2")); + return; + } + + if ( ((CButton*)GetDlgItem(IDC_LINEDATA_RADIO))->GetCheck() == 1) + { + m_iDataType = 0; + + GetDlgItem(IDC_DATAPARAM1_EDIT)->GetWindowText(szBuff,254); +// m_fLineSlope = (float)_tstof(szBuff); + m_fLineSlope = (float)_tcstod(szBuff, NULL); + GetDlgItem(IDC_DATAPARAM2_EDIT)->GetWindowText(szBuff,254); +// m_fLineOffset = (float)_tstof(szBuff); + m_fLineOffset = (float)_tcstod(szBuff, NULL); + } + else if ( ((CButton*)GetDlgItem(IDC_SINEDATA_RADIO))->GetCheck() == 1) + { + m_iDataType = 1; + + GetDlgItem(IDC_DATAPARAM1_EDIT)->GetWindowText(szBuff,254); +// m_fSineAmplitude = (float)_tstof(szBuff); + m_fSineAmplitude = (float)_tcstod(szBuff, NULL); + GetDlgItem(IDC_DATAPARAM2_EDIT)->GetWindowText(szBuff,254); +// m_fSinePeriod = (float)_tstof(szBuff); + m_fSinePeriod = (float)_tcstod(szBuff, NULL); + if (m_fSinePeriod == 0) + { + MessageBox(_T("Sine period cannot be 0"),_T("Error")); + return; + } + } + else + { + m_iDataType = 2; + +#ifdef UNICODE + GetDlgItem(IDC_DATAPARAM1_EDIT)->GetWindowText(szBuff,254); + m_iRandMinVal = _wtoi(szBuff); + GetDlgItem(IDC_DATAPARAM2_EDIT)->GetWindowText(szBuff,254); + m_iRandMaxVal = _wtoi(szBuff); +#else + GetDlgItem(IDC_DATAPARAM1_EDIT)->GetWindowText(szBuff,254); + m_iRandMinVal = atoi(szBuff); + GetDlgItem(IDC_DATAPARAM2_EDIT)->GetWindowText(szBuff,254); + m_iRandMaxVal = atoi(szBuff); +#endif + + if (m_iRandMaxVal < m_iRandMinVal) + { + MessageBox(_T("Max random value should be > Min random value")); + return; + } + } + + CDialog::OnOK(); +} + +BOOL CSeriesPropDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_SeriesTypeCombo.SetCurSel(0); + m_HorizAxisCombo.SetCurSel(0); + m_VertAxisCombo.SetCurSel(0); + ((CButton*)GetDlgItem(IDC_LINEDATA_RADIO))->SetCheck(1); + + GetDlgItem(IDC_MINXVALUE_EDIT)->SetWindowText(_T("0.0")); + GetDlgItem(IDC_MAXXVALUE_EDIT)->SetWindowText(_T("100.0")); + + GetDlgItem(IDC_DATAPARAM1_EDIT)->SetWindowText(_T("1.0")); + GetDlgItem(IDC_DATAPARAM2_EDIT)->SetWindowText(_T("0.0")); + GetDlgItem(IDC_POINTSNUMBER_EDIT)->SetWindowText(_T("100")); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CSeriesPropDlg::OnSelectLineData() +{ + GetDlgItem(IDC_DATAPARAM1_TEXT)->SetWindowText(_T("Line Slope бÂÊ:")); + GetDlgItem(IDC_DATAPARAM2_TEXT)->SetWindowText(_T("Line Offset Æ«ÒÆÁ¿:")); + GetDlgItem(IDC_DATAPARAM1_EDIT)->SetWindowText(_T("1.0")); + GetDlgItem(IDC_DATAPARAM2_EDIT)->SetWindowText(_T("0.0")); + GetDlgItem(IDC_POINTSNUMBER_EDIT)->SetWindowText(_T("100")); +} + +void CSeriesPropDlg::OnSelectRandomData() +{ + + GetDlgItem(IDC_DATAPARAM1_TEXT)->SetWindowText(_T("Min Y value:")); + GetDlgItem(IDC_DATAPARAM2_TEXT)->SetWindowText(_T("Max Y value:")); + GetDlgItem(IDC_DATAPARAM1_EDIT)->SetWindowText(_T("0")); + GetDlgItem(IDC_DATAPARAM2_EDIT)->SetWindowText(_T("100")); + GetDlgItem(IDC_POINTSNUMBER_EDIT)->SetWindowText(_T("100")); +} + +void CSeriesPropDlg::OnSelectSineData() +{ + GetDlgItem(IDC_DATAPARAM1_TEXT)->SetWindowText(_T("Sine Amplitude ÕýÏÒÕñ·ù:")); + GetDlgItem(IDC_DATAPARAM2_TEXT)->SetWindowText(_T("Sine Period ÕýÏÒÖÜÆÚ:")); + GetDlgItem(IDC_DATAPARAM1_EDIT)->SetWindowText(_T("3.0")); + GetDlgItem(IDC_DATAPARAM2_EDIT)->SetWindowText(_T("5.0")); + GetDlgItem(IDC_POINTSNUMBER_EDIT)->SetWindowText(_T("1000")); +} diff --git a/ChartDemo/SeriesPropDlg.h b/ChartDemo/SeriesPropDlg.h new file mode 100644 index 0000000..b739783 --- /dev/null +++ b/ChartDemo/SeriesPropDlg.h @@ -0,0 +1,85 @@ +#if !defined(AFX_SERIESPROPDLG_H__EFFE6C6F_39A1_42E7_9B35_1EE66D5AC520__INCLUDED_) +#define AFX_SERIESPROPDLG_H__EFFE6C6F_39A1_42E7_9B35_1EE66D5AC520__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// SeriesPropDlg.h : header file +// + +#include "ChartString.h" +#include "ColourPicker.h" + +///////////////////////////////////////////////////////////////////////////// +// CSeriesPropDlg dialog + +class CSeriesPropDlg : public CDialog +{ +// Construction +public: +// std::string GetSeriesName() const { return m_strSeriesName; } +// int GetSeriesType() const { return m_iSeriesType; } +// COLORREF GetSeriesColour() const { return m_SeriesColour; } + + CSeriesPropDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CSeriesPropDlg) + enum { IDD = IDD_SERIESPROP_DLG }; + CComboBox m_VertAxisCombo; + CComboBox m_HorizAxisCombo; + CColourPicker m_ColourSelect; + CComboBox m_SeriesTypeCombo; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSeriesPropDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CSeriesPropDlg) + virtual void OnOK(); + virtual BOOL OnInitDialog(); + afx_msg void OnSelectLineData(); + afx_msg void OnSelectRandomData(); + afx_msg void OnSelectSineData(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +public: + TChartString m_strSeriesName; + int m_iSeriesType; + COLORREF m_SeriesColour; + + int m_iVertAxis; + int m_iHorizAxis; + + int m_iDataType; + int m_iPointsNumber; + float m_fMaxXValue; + float m_fMinXValue; + + //Line data: + float m_fLineSlope; + float m_fLineOffset; + + // Sine wave data: + float m_fSineAmplitude; + float m_fSinePeriod; + + // Random values data: + int m_iRandMinVal; + int m_iRandMaxVal; +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_SERIESPROPDLG_H__EFFE6C6F_39A1_42E7_9B35_1EE66D5AC520__INCLUDED_) diff --git a/ChartDemo/StdAfx.cpp b/ChartDemo/StdAfx.cpp new file mode 100644 index 0000000..6d1be81 --- /dev/null +++ b/ChartDemo/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// ChartDemo.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/ChartDemo/StdAfx.h b/ChartDemo/StdAfx.h new file mode 100644 index 0000000..45e4576 --- /dev/null +++ b/ChartDemo/StdAfx.h @@ -0,0 +1,28 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__F1B266DB_B914_41ED_B713_A3CB4AC72DE8__INCLUDED_) +#define AFX_STDAFX_H__F1B266DB_B914_41ED_B713_A3CB4AC72DE8__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#pragma warning (disable:4786) + +#endif // !defined(AFX_STDAFX_H__F1B266DB_B914_41ED_B713_A3CB4AC72DE8__INCLUDED_) diff --git a/ChartDemo/SurfacePropDialog.cpp b/ChartDemo/SurfacePropDialog.cpp new file mode 100644 index 0000000..777b51e --- /dev/null +++ b/ChartDemo/SurfacePropDialog.cpp @@ -0,0 +1,62 @@ +// SurfacePropDialog.cpp : implementation file +// + +#include "stdafx.h" +#include "chartdemo.h" +#include "SurfacePropDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CSurfacePropDialog dialog + + +CSurfacePropDialog::CSurfacePropDialog(CWnd* pParent /*=NULL*/) + : CDialog(CSurfacePropDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CSurfacePropDialog) + m_iHorizSurf = -1; + m_FillStyle = -1; + //}}AFX_DATA_INIT +} + + +void CSurfacePropDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CSurfacePropDialog) + DDX_Radio(pDX, IDC_HORIZONTAL_RADIO, m_iHorizSurf); + DDX_CBIndex(pDX, IDC_FILLSTYLE_COMBO, m_FillStyle); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CSurfacePropDialog, CDialog) + //{{AFX_MSG_MAP(CSurfacePropDialog) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CSurfacePropDialog message handlers + +BOOL CSurfacePropDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_FillStyle = 0; + m_iHorizSurf = 0; + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CSurfacePropDialog::OnOK() +{ + UpdateData(TRUE); + CDialog::OnOK(); +} diff --git a/ChartDemo/SurfacePropDialog.h b/ChartDemo/SurfacePropDialog.h new file mode 100644 index 0000000..37e2e39 --- /dev/null +++ b/ChartDemo/SurfacePropDialog.h @@ -0,0 +1,48 @@ +#if !defined(AFX_SURFACEPROPDIALOG_H__88893012_E2F3_477F_833A_B3D7B10CC8A8__INCLUDED_) +#define AFX_SURFACEPROPDIALOG_H__88893012_E2F3_477F_833A_B3D7B10CC8A8__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// SurfacePropDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CSurfacePropDialog dialog + +class CSurfacePropDialog : public CDialog +{ +// Construction +public: + CSurfacePropDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CSurfacePropDialog) + enum { IDD = IDD_SURFACEPROP_DLG }; + int m_iHorizSurf; + int m_FillStyle; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSurfacePropDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CSurfacePropDialog) + virtual BOOL OnInitDialog(); + virtual void OnOK(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_SURFACEPROPDIALOG_H__88893012_E2F3_477F_833A_B3D7B10CC8A8__INCLUDED_) diff --git a/ChartDemo/res/ChartDemo.ico b/ChartDemo/res/ChartDemo.ico new file mode 100644 index 0000000000000000000000000000000000000000..7eef0bcbe6580a6f464d688906172c2d9de44262 GIT binary patch literal 1078 zcmc&zF>b>!3}jLb9s)T}@Kod(893@u8ajANzT`op9^o+)S?=nU(FD@%0s)Sg^oyC8{H z9myetc;MEP)59v(LMa~xK8Yu^jIR*H22uCFiq5%C{s7(PJi>o15i^bmX4(vPxWAio z9ryY#AU_jfnd047-@`)XzL?%iS$gQyFP{44kS9X)fN{{QoL~hO-&=q&20Zr*cxFAt PkaNE{wR~2C$NfnjhSXWT literal 0 HcmV?d00001 diff --git a/ChartDemo/res/ChartDemo.rc2 b/ChartDemo/res/ChartDemo.rc2 new file mode 100644 index 0000000..4c72645 --- /dev/null +++ b/ChartDemo/res/ChartDemo.rc2 @@ -0,0 +1,13 @@ +// +// CHARTDEMO.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/ChartDemo/resource.h b/ChartDemo/resource.h new file mode 100644 index 0000000..82be42d --- /dev/null +++ b/ChartDemo/resource.h @@ -0,0 +1,76 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ChartDemo.rc +// +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_CHARTDEMO_DIALOG 102 +#define IDR_MAINFRAME 128 +#define IDD_SERIESPROP_DLG 131 +#define IDD_LINEPROP_DLG 135 +#define IDD_SURFACEPROP_DLG 137 +#define IDD_POINTPROP_DLG 139 +#define IDC_CHARTCTRL 1001 +#define IDC_SERIES_GROUP 1007 +#define IDC_ADDSERIES 1009 +#define IDC_SERIESNAME_EDIT 1010 +#define IDC_SERIESTYPE_COMBO 1011 +#define IDC_SERIESCOLOUR_BTN 1012 +#define IDC_SERIES_LIST 1013 +#define IDC_GENERAL_GROUP 1014 +#define IDC_LEGENDVIS_CHECK 1015 +#define IDC_BKGND_COLBTN 1016 +#define IDC_AXIS_GROUP 1017 +#define IDC_LEFTAXIS_RADIO 1018 +#define IDC_BOTTOMAXIS_RADIO 1019 +#define IDC_RIGHTAXIS_RADIO 1020 +#define IDC_TOPAXIS_RADIO 1021 +#define IDC_AXISVISIBLE_CHECK 1022 +#define IDC_AXISAUTOMATIC_CHECK 1023 +#define IDC_AXISGRIDVIS_CHECK 1024 +#define IDC_AXISMINVAL_EDIT 1025 +#define IDC_AXISMAXVAL_EDIT 1026 +#define IDC_AXISLOGARITHMIC_CHECK 1027 +#define IDC_AXISMINVAL_STATIC 1028 +#define IDC_AXISMAXVAL_STATIC 1029 +#define IDC_TITLE_EDIT 1033 +#define IDC_VERTICALAXIS_COMBO 1034 +#define IDC_HORIZONTALAXIS_COMBO 1035 +#define IDC_LINEDATA_RADIO 1036 +#define IDC_SINEDATA_RADIO 1037 +#define IDC_RANDOMDATA_RADIO 1038 +#define IDC_MINXVALUE_EDIT 1039 +#define IDC_MAXXVALUE_EDIT 1040 +#define IDC_POINTSNUMBER_EDIT 1043 +#define IDC_DATAPARAM1_EDIT 1044 +#define IDC_DATAPARAM2_EDIT 1045 +#define IDC_DATAPARAM1_TEXT 1046 +#define IDC_DATAPARAM2_TEXT 1047 +#define IDC_AXISINVERTED_CHECK 1048 +#define IDC_AXISLABEL_EDIT 1049 +#define IDC_DELETESERIES 1050 +#define IDC_CHART2 1052 +#define IDC_PAN_CHECK 1055 +#define IDC_ZOOM_CHECK 1056 +#define IDC_PENSTYLE_COMBO 1058 +#define IDC_LINEWIDTH_EDIT 1059 +#define IDC_HORIZONTAL_RADIO 1060 +#define IDC_RADIO2 1061 +#define IDC_FILLSTYLE_COMBO 1062 +#define IDC_POINTTYPE_COMBO 1063 +#define IDC_POINTWIDTH_EDIT 1064 +#define IDC_POINTHEIGHT_EDIT 1065 +#define IDC_CHECK1 1066 +#define IDC_AXISSCROLLBAR_CHECK 1066 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 141 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1067 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..b6394f9 --- /dev/null +++ b/README.MD @@ -0,0 +1,32 @@ + + + +##### High-speed Charting Control + +[Fork From codeproject](https://www.codeproject.com/Articles/14075/High-speed-Charting-Control) + + +##### 说明 + +基于MFC的高速图表控件 + + +##### 图片显示 + + + +![sdfsdfs](pic1.jpg) + + + +![sdfsdfs](pic2.jpg) + + +##### è‹±æ–‡ä»‹ç» + +[https://www.codeproject.com/Articles/14075/High-speed-Charting-Control](https://www.codeproject.com/Articles/14075/High-speed-Charting-Control) + + +##### ChartDemo Documentation + +[ChartDemo\Doc\html\index.html](./ChartDemo/Doc/html/index.html) \ No newline at end of file diff --git a/pic1.jpg b/pic1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8ca6e050607a3860c2adb0da6b0594a92396f3ac GIT binary patch literal 193876 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�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

8{LLkMa0T_tD9NDizUB;?#!Ui9QQ`dK^+Q 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 z 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

f@B>Gp?u7`&h$=8y27%Acdi5eXhMP{XLa%| zJI2_MejvX2_&`~hPN3rL=~?rOQ}6co4ZU0?CnVD^4}q2A9RW;XPCRKh2>n7+a|id$ zU%MJ4?A^J#abD5IvlJ<6v3gfIKN-HhA!VqR&w+EQD@&J5s6-7wc#!_ai@aCLv3`%d zEVNyn>Ej(tk&`|tV4R>XCp6Mll3y~JZq9Eo#MEU1y7QYZ*VJ4Y9-j(2)1JyOQ9}Q% zHPUT%zchMoKfH#TVfehkKvz%n=rdcVKu>Gl%Hk2}?^QWh-LgC3Cb|{j6y~2tLfgn% zfP2>)GLY9^0k0iox?Em=#&GWD1M7*4;olz41zYRh_I!Bv{TpZAiCXvmyd1d*%B7Oe z{WsZzQ+S?3=1)9sTVpq$k8+)^QmeshS&zC*F6gT{Bs|{e0#2xUBmFHf0Y){R9CsyT z9f$e&Q^smxwlljola+(lASs9W`Yt`gq#5pMJ@qGb%UW!zm)_;*Qk5KXy4h(_;^MDR zrTjSp$;iOA;+nCSCe5rOwolBsu{H5UEZu%vQvsva%&uEftSx+0Dh=5>>cOWi_>*i* zq8g$SvZQ(TjLE(FXPB0PpZru0AG9T!!Gj8Q^^hyne#$fUr*cXVH=mz!!{^pZA>m@g z3Mv8@nxC?E#qHMj8M!+}qThc4THBxc70^n0wZrx+fZ@(AfPMwMfpj1C-)DHdpW@Gc zHEp;TdV%2+>;H5ALAFCOZ5U&JhzXU3%3Tvs(v@IgNIOHF@v|DZ+_ud2Vr)wi->zPf10TC*mQF|mAN$cnBM^B(1%+;W zDb2IN5H}z`VufyD5gwypC2X#P+z8)x`kEzqR~K{WC!K73JgM=yWQcp?lKStVnSxB9 zM$uGq#(2?~Xlvx*>&f2Ugg7YN4mV%}=G_w%jpELmk>WxCTB_ffrB{bD$K^Kd-3hqA zx1zU|{wu)u#2x6>>CS6cUVb0%zDbI!UAgn6J^j%0{_=y-+pRLs;?6ejmu)mlV%|6m z7XQMnGd=HQyE5|gAL8Ht+!Vs=>6jEdQN7zEg)s8-7g(^GJ5v|IpznAx z8�qiF@RTvHW*F2JR}|bX^|i=< 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