Avoid potential negative array index access to cached text.
[LibreOffice.git] / extensions / source / scanner / grid.cxx
blob7d87010ea1527b6a75278f9b8f1a95ebd4d1d096
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <o3tl/sprintf.hxx>
22 #include <osl/thread.h>
23 #include <rtl/math.hxx>
25 #include <bitmaps.hlst>
26 #include <cmath>
28 #include "grid.hxx"
29 #include <vcl/bitmapex.hxx>
30 #include <vcl/customweld.hxx>
31 #include <vcl/event.hxx>
32 #include <vcl/settings.hxx>
33 #include <vcl/svapp.hxx>
35 #include <algorithm>
36 #include <limits>
37 #include <memory>
39 class GridWindow : public weld::CustomWidgetController
41 // helper class for handles
42 struct impHandle
44 Point maPos;
45 sal_uInt16 mnOffX;
46 sal_uInt16 mnOffY;
48 impHandle(const Point& rPos, sal_uInt16 nX, sal_uInt16 nY)
49 : maPos(rPos), mnOffX(nX), mnOffY(nY)
53 bool operator<(const impHandle& rComp) const
55 return (maPos.X() < rComp.maPos.X());
58 void draw(vcl::RenderContext& rRenderContext, const BitmapEx& rBitmapEx)
60 const Point aOffset(rRenderContext.PixelToLogic(Point(mnOffX, mnOffY)));
61 rRenderContext.DrawBitmapEx(maPos - aOffset, rBitmapEx);
64 bool isHit(OutputDevice const & rWin, const Point& rPos)
66 const Point aOffset(rWin.PixelToLogic(Point(mnOffX, mnOffY)));
67 const tools::Rectangle aTarget(maPos - aOffset, maPos + aOffset);
68 return aTarget.Contains(rPos);
72 tools::Rectangle m_aGridArea;
74 double m_fMinX;
75 double m_fMinY;
76 double m_fMaxX;
77 double m_fMaxY;
79 double m_fChunkX;
80 double m_fMinChunkX;
81 double m_fChunkY;
82 double m_fMinChunkY;
84 double* m_pXValues;
85 double* m_pOrigYValues;
86 int m_nValues;
87 std::unique_ptr<double[]> m_pNewYValues;
89 sal_uInt16 m_BmOffX;
90 sal_uInt16 m_BmOffY;
92 bool m_bCutValues;
94 // stuff for handles
95 using Handles = std::vector<impHandle>;
96 static constexpr auto npos = std::numeric_limits<Handles::size_type>::max();
97 Handles m_aHandles;
98 Handles::size_type m_nDragIndex;
100 BitmapEx m_aMarkerBitmap;
102 Point transform( double x, double y );
103 void transform( const Point& rOriginal, double& x, double& y );
105 double findMinX();
106 double findMinY();
107 double findMaxX();
108 double findMaxY();
110 void drawGrid(vcl::RenderContext& rRenderContext);
111 void drawOriginal(vcl::RenderContext& rRenderContext);
112 void drawNew(vcl::RenderContext& rRenderContext);
113 void drawHandles(vcl::RenderContext& rRenderContext);
115 void computeExtremes();
116 static void computeChunk( double fMin, double fMax, double& fChunkOut, double& fMinChunkOut );
117 void computeNew();
118 static double interpolate( double x, double const * pNodeX, double const * pNodeY, int nNodes );
120 virtual bool MouseMove( const MouseEvent& ) override;
121 virtual bool MouseButtonDown( const MouseEvent& ) override;
122 virtual bool MouseButtonUp( const MouseEvent& ) override;
123 void onResize();
124 virtual void Resize() override;
125 virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
126 void drawLine(vcl::RenderContext& rRenderContext, double x1, double y1, double x2, double y2);
127 public:
128 GridWindow();
129 void Init(double* pXValues, double* pYValues, int nValues, bool bCutValues, const BitmapEx &rMarkerBitmap);
130 virtual ~GridWindow() override;
132 void setBoundings( double fMinX, double fMinY, double fMaxX, double fMaxY );
134 double* getNewYValues() { return m_pNewYValues.get(); }
136 void ChangeMode(ResetType nType);
138 virtual void Paint( vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect ) override;
141 GridWindow::GridWindow()
142 : m_aGridArea(50, 15, 100, 100)
143 , m_fMinX(0.0)
144 , m_fMinY(0.0)
145 , m_fMaxX(0.0)
146 , m_fMaxY(0.0)
147 , m_fChunkX(0.0)
148 , m_fMinChunkX(0.0)
149 , m_fChunkY(0.0)
150 , m_fMinChunkY(0.0)
151 , m_pXValues(nullptr)
152 , m_pOrigYValues(nullptr)
153 , m_nValues(0)
154 , m_BmOffX(0)
155 , m_BmOffY(0)
156 , m_bCutValues(false)
157 , m_nDragIndex(npos)
161 void GridWindow::Init(double* pXValues, double* pYValues, int nValues, bool bCutValues, const BitmapEx &rMarkerBitmap)
163 m_aMarkerBitmap = rMarkerBitmap;
164 m_pXValues = pXValues;
165 m_pOrigYValues = pYValues;
166 m_nValues = nValues;
167 m_bCutValues = bCutValues;
169 onResize();
171 if (m_pOrigYValues && m_nValues)
173 m_pNewYValues.reset(new double[ m_nValues ]);
174 memcpy( m_pNewYValues.get(), m_pOrigYValues, sizeof( double ) * m_nValues );
177 setBoundings( 0, 0, 1023, 1023 );
178 computeExtremes();
180 // create left and right marker as first and last entry
181 m_BmOffX = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Width() >> 1);
182 m_BmOffY = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Height() >> 1);
183 m_aHandles.push_back(impHandle(transform(findMinX(), findMinY()), m_BmOffX, m_BmOffY));
184 m_aHandles.push_back(impHandle(transform(findMaxX(), findMaxY()), m_BmOffX, m_BmOffY));
187 void GridWindow::Resize()
189 onResize();
192 void GridWindow::onResize()
194 Size aSize = GetOutputSizePixel();
195 m_aGridArea.setWidth( aSize.Width() - 80 );
196 m_aGridArea.setHeight( aSize.Height() - 40 );
199 void GridWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
201 Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(240, 200), MapMode(MapUnit::MapAppFont)));
202 pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
203 CustomWidgetController::SetDrawingArea(pDrawingArea);
204 SetOutputSizePixel(aSize);
207 GridDialog::GridDialog(weld::Window* pParent, double* pXValues, double* pYValues, int nValues)
208 : GenericDialogController(pParent, "modules/scanner/ui/griddialog.ui", "GridDialog")
209 , m_xResetTypeBox(m_xBuilder->weld_combo_box("resetTypeCombobox"))
210 , m_xResetButton(m_xBuilder->weld_button("resetButton"))
211 , m_xGridWindow(new GridWindow)
212 , m_xGridWindowWND(new weld::CustomWeld(*m_xBuilder, "gridwindow", *m_xGridWindow))
214 m_xGridWindow->Init(pXValues, pYValues, nValues, true/*bCutValues*/, BitmapEx(RID_SCANNER_HANDLE));
215 m_xResetTypeBox->set_active(0);
216 m_xResetButton->connect_clicked( LINK( this, GridDialog, ClickButtonHdl ) );
219 GridDialog::~GridDialog()
223 GridWindow::~GridWindow()
225 m_pNewYValues.reset();
228 double GridWindow::findMinX()
230 if( ! m_pXValues )
231 return 0.0;
232 double fMin = m_pXValues[0];
233 for( int i = 1; i < m_nValues; i++ )
234 if( m_pXValues[ i ] < fMin )
235 fMin = m_pXValues[ i ];
236 return fMin;
239 double GridWindow::findMinY()
241 if( ! m_pNewYValues )
242 return 0.0;
243 double fMin = m_pNewYValues[0];
244 for( int i = 1; i < m_nValues; i++ )
245 if( m_pNewYValues[ i ] < fMin )
246 fMin = m_pNewYValues[ i ];
247 return fMin;
251 double GridWindow::findMaxX()
253 if( ! m_pXValues )
254 return 0.0;
255 double fMax = m_pXValues[0];
256 for( int i = 1; i < m_nValues; i++ )
257 if( m_pXValues[ i ] > fMax )
258 fMax = m_pXValues[ i ];
259 return fMax;
263 double GridWindow::findMaxY()
265 if( ! m_pNewYValues )
266 return 0.0;
267 double fMax = m_pNewYValues[0];
268 for( int i = 1; i < m_nValues; i++ )
269 if( m_pNewYValues[ i ] > fMax )
270 fMax = m_pNewYValues[ i ];
271 return fMax;
275 void GridWindow::computeExtremes()
277 if( !(m_nValues && m_pXValues && m_pOrigYValues) )
278 return;
280 m_fMaxX = m_fMinX = m_pXValues[0];
281 m_fMaxY = m_fMinY = m_pOrigYValues[0];
282 for( int i = 1; i < m_nValues; i++ )
284 if( m_pXValues[ i ] > m_fMaxX )
285 m_fMaxX = m_pXValues[ i ];
286 else if( m_pXValues[ i ] < m_fMinX )
287 m_fMinX = m_pXValues[ i ];
288 if( m_pOrigYValues[ i ] > m_fMaxY )
289 m_fMaxY = m_pOrigYValues[ i ];
290 else if( m_pOrigYValues[ i ] < m_fMinY )
291 m_fMinY = m_pOrigYValues[ i ];
293 setBoundings( m_fMinX, m_fMinY, m_fMaxX, m_fMaxY );
297 Point GridWindow::transform( double x, double y )
299 Point aRet;
301 aRet.setX( static_cast<tools::Long>( ( x - m_fMinX ) *
302 static_cast<double>(m_aGridArea.GetWidth()) / ( m_fMaxX - m_fMinX )
303 + m_aGridArea.Left() ) );
304 aRet.setY( static_cast<tools::Long>(
305 m_aGridArea.Bottom() -
306 ( y - m_fMinY ) *
307 static_cast<double>(m_aGridArea.GetHeight()) / ( m_fMaxY - m_fMinY ) ) );
308 return aRet;
311 void GridWindow::transform( const Point& rOriginal, double& x, double& y )
313 const tools::Long nWidth = m_aGridArea.GetWidth();
314 const tools::Long nHeight = m_aGridArea.GetHeight();
315 if (!nWidth || !nHeight)
316 return;
317 x = ( rOriginal.X() - m_aGridArea.Left() ) * (m_fMaxX - m_fMinX) / static_cast<double>(nWidth) + m_fMinX;
318 y = ( m_aGridArea.Bottom() - rOriginal.Y() ) * (m_fMaxY - m_fMinY) / static_cast<double>(nHeight) + m_fMinY;
321 void GridWindow::drawLine(vcl::RenderContext& rRenderContext, double x1, double y1, double x2, double y2 )
323 rRenderContext.DrawLine(transform(x1, y1), transform(x2, y2));
326 void GridWindow::computeChunk( double fMin, double fMax, double& fChunkOut, double& fMinChunkOut )
328 // get a nice chunk size like 10, 100, 25 or such
329 fChunkOut = ( fMax - fMin ) / 6.0;
330 int logchunk = static_cast<int>(std::log10( fChunkOut ));
331 int nChunk = static_cast<int>( fChunkOut / std::exp( static_cast<double>(logchunk-1) * M_LN10 ) );
332 if( nChunk >= 75 )
333 nChunk = 100;
334 else if( nChunk >= 35 )
335 nChunk = 50;
336 else if ( nChunk > 20 )
337 nChunk = 25;
338 else if ( nChunk >= 13 )
339 nChunk = 20;
340 else if( nChunk > 5 )
341 nChunk = 10;
342 else
343 nChunk = 5;
344 fChunkOut = static_cast<double>(nChunk) * exp( static_cast<double>(logchunk-1) * M_LN10 );
345 // compute whole chunks fitting into fMin
346 nChunk = static_cast<int>( fMin / fChunkOut );
347 fMinChunkOut = static_cast<double>(nChunk) * fChunkOut;
348 while( fMinChunkOut < fMin )
349 fMinChunkOut += fChunkOut;
353 void GridWindow::computeNew()
355 if(2 == m_aHandles.size())
357 // special case: only left and right markers
358 double xleft, yleft;
359 double xright, yright;
360 transform(m_aHandles[0].maPos, xleft, yleft);
361 transform(m_aHandles[1].maPos, xright, yright );
362 double factor = (yright-yleft)/(xright-xleft);
363 for( int i = 0; i < m_nValues; i++ )
365 m_pNewYValues[ i ] = yleft + ( m_pXValues[ i ] - xleft )*factor;
368 else
370 // sort markers
371 std::sort(m_aHandles.begin(), m_aHandles.end());
372 const int nSorted = m_aHandles.size();
373 int i;
375 // get node arrays
376 std::unique_ptr<double[]> nodex(new double[ nSorted ]);
377 std::unique_ptr<double[]> nodey(new double[ nSorted ]);
379 for( i = 0; i < nSorted; i++ )
380 transform( m_aHandles[i].maPos, nodex[ i ], nodey[ i ] );
382 for( i = 0; i < m_nValues; i++ )
384 double x = m_pXValues[ i ];
385 m_pNewYValues[ i ] = interpolate( x, nodex.get(), nodey.get(), nSorted );
386 if( m_bCutValues )
388 if( m_pNewYValues[ i ] > m_fMaxY )
389 m_pNewYValues[ i ] = m_fMaxY;
390 else if( m_pNewYValues[ i ] < m_fMinY )
391 m_pNewYValues[ i ] = m_fMinY;
398 double GridWindow::interpolate(
399 double x,
400 double const * pNodeX,
401 double const * pNodeY,
402 int nNodes )
404 // compute Lagrange interpolation
405 double ret = 0;
406 for( int i = 0; i < nNodes; i++ )
408 double sum = pNodeY[ i ];
409 for( int n = 0; n < nNodes; n++ )
411 if( n != i )
413 sum *= x - pNodeX[ n ];
414 sum /= pNodeX[ i ] - pNodeX[ n ];
417 ret += sum;
419 return ret;
422 void GridDialog::setBoundings(double fMinX, double fMinY, double fMaxX, double fMaxY)
424 m_xGridWindow->setBoundings(fMinX, fMinY, fMaxX, fMaxY);
427 void GridWindow::setBoundings(double fMinX, double fMinY, double fMaxX, double fMaxY)
429 m_fMinX = fMinX;
430 m_fMinY = fMinY;
431 m_fMaxX = fMaxX;
432 m_fMaxY = fMaxY;
434 computeChunk( m_fMinX, m_fMaxX, m_fChunkX, m_fMinChunkX );
435 computeChunk( m_fMinY, m_fMaxY, m_fChunkY, m_fMinChunkY );
438 void GridWindow::drawGrid(vcl::RenderContext& rRenderContext)
440 char pBuf[256];
441 rRenderContext.SetLineColor(COL_BLACK);
442 // draw vertical lines
443 for (double fX = m_fMinChunkX; fX < m_fMaxX; fX += m_fChunkX)
445 drawLine(rRenderContext, fX, m_fMinY, fX, m_fMaxY);
446 // draw tickmarks
447 Point aPt = transform(fX, m_fMinY);
448 o3tl::sprintf(pBuf, "%g", fX);
449 OUString aMark(pBuf, strlen(pBuf), osl_getThreadTextEncoding());
450 Size aTextSize(rRenderContext.GetTextWidth(aMark), rRenderContext.GetTextHeight());
451 aPt.AdjustX( -(aTextSize.Width() / 2) );
452 aPt.AdjustY(aTextSize.Height() / 2 );
453 rRenderContext.DrawText(aPt, aMark);
455 // draw horizontal lines
456 for (double fY = m_fMinChunkY; fY < m_fMaxY; fY += m_fChunkY)
458 drawLine(rRenderContext, m_fMinX, fY, m_fMaxX, fY);
459 // draw tickmarks
460 Point aPt = transform(m_fMinX, fY);
461 o3tl::sprintf(pBuf, "%g", fY);
462 OUString aMark(pBuf, strlen(pBuf), osl_getThreadTextEncoding());
463 Size aTextSize(rRenderContext.GetTextWidth(aMark), rRenderContext.GetTextHeight());
464 aPt.AdjustX( -(aTextSize.Width() + 2) );
465 aPt.AdjustY( -(aTextSize.Height() / 2) );
466 rRenderContext.DrawText(aPt, aMark);
469 // draw boundings
470 drawLine(rRenderContext, m_fMinX, m_fMinY, m_fMaxX, m_fMinY);
471 drawLine(rRenderContext, m_fMinX, m_fMaxY, m_fMaxX, m_fMaxY);
472 drawLine(rRenderContext, m_fMinX, m_fMinY, m_fMinX, m_fMaxY);
473 drawLine(rRenderContext, m_fMaxX, m_fMinY, m_fMaxX, m_fMaxY);
476 void GridWindow::drawOriginal(vcl::RenderContext& rRenderContext)
478 if (m_nValues && m_pXValues && m_pOrigYValues)
480 rRenderContext.SetLineColor(COL_RED);
481 for (int i = 0; i < m_nValues - 1; i++)
483 drawLine(rRenderContext,
484 m_pXValues[i], m_pOrigYValues[i],
485 m_pXValues[i + 1], m_pOrigYValues[i + 1]);
490 void GridWindow::drawNew(vcl::RenderContext& rRenderContext)
492 if (m_nValues && m_pXValues && m_pNewYValues)
494 rRenderContext.SetClipRegion(vcl::Region(m_aGridArea));
495 rRenderContext.SetLineColor(COL_YELLOW);
496 for (int i = 0; i < m_nValues - 1; i++)
498 drawLine(rRenderContext,
499 m_pXValues[i], m_pNewYValues[i],
500 m_pXValues[i + 1], m_pNewYValues[i + 1]);
502 rRenderContext.SetClipRegion();
506 void GridWindow::drawHandles(vcl::RenderContext& rRenderContext)
508 for(impHandle & rHandle : m_aHandles)
510 rHandle.draw(rRenderContext, m_aMarkerBitmap);
514 void GridWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
516 rRenderContext.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetDialogColor()));
517 drawGrid(rRenderContext);
518 drawOriginal(rRenderContext);
519 drawNew(rRenderContext);
520 drawHandles(rRenderContext);
523 bool GridWindow::MouseMove( const MouseEvent& rEvt )
525 if( rEvt.GetButtons() != MOUSE_LEFT || m_nDragIndex == npos )
526 return false;
528 Point aPoint( rEvt.GetPosPixel() );
530 if( m_nDragIndex == 0 || m_nDragIndex == m_aHandles.size() - 1)
532 aPoint.setX( m_aHandles[m_nDragIndex].maPos.X() );
534 else
536 if(aPoint.X() < m_aGridArea.Left())
537 aPoint.setX( m_aGridArea.Left() );
538 else if(aPoint.X() > m_aGridArea.Right())
539 aPoint.setX( m_aGridArea.Right() );
542 if( aPoint.Y() < m_aGridArea.Top() )
543 aPoint.setY( m_aGridArea.Top() );
544 else if( aPoint.Y() > m_aGridArea.Bottom() )
545 aPoint.setY( m_aGridArea.Bottom() );
547 if( aPoint != m_aHandles[m_nDragIndex].maPos )
549 m_aHandles[m_nDragIndex].maPos = aPoint;
550 Invalidate( m_aGridArea );
553 return false;
556 bool GridWindow::MouseButtonUp( const MouseEvent& rEvt )
558 if( rEvt.GetButtons() == MOUSE_LEFT )
560 if( m_nDragIndex != npos )
562 m_nDragIndex = npos;
563 computeNew();
564 Invalidate(m_aGridArea);
568 return false;
571 bool GridWindow::MouseButtonDown( const MouseEvent& rEvt )
573 Point aPoint( rEvt.GetPosPixel() );
574 Handles::size_type nMarkerIndex = npos;
576 for(Handles::size_type a(0); nMarkerIndex == npos && a < m_aHandles.size(); a++)
578 if(m_aHandles[a].isHit(GetDrawingArea()->get_ref_device(), aPoint))
580 nMarkerIndex = a;
584 if( rEvt.GetButtons() == MOUSE_LEFT )
586 // user wants to drag a button
587 if( nMarkerIndex != npos )
589 m_nDragIndex = nMarkerIndex;
592 else if( rEvt.GetButtons() == MOUSE_RIGHT )
594 // user wants to add/delete a button
595 if( nMarkerIndex != npos )
597 if( nMarkerIndex != 0 && nMarkerIndex != m_aHandles.size() - 1)
599 // delete marker under mouse
600 if( m_nDragIndex == nMarkerIndex )
601 m_nDragIndex = npos;
603 m_aHandles.erase(m_aHandles.begin() + nMarkerIndex);
606 else
608 m_BmOffX = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Width() >> 1);
609 m_BmOffY = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Height() >> 1);
610 m_aHandles.push_back(impHandle(aPoint, m_BmOffX, m_BmOffY));
613 computeNew();
614 Invalidate(m_aGridArea);
617 return false;
620 void GridWindow::ChangeMode(ResetType nType)
622 switch( nType )
624 case ResetType::LINEAR_ASCENDING:
626 for( int i = 0; i < m_nValues; i++ )
628 m_pNewYValues[ i ] = m_fMinY + (m_fMaxY-m_fMinY)/(m_fMaxX-m_fMinX)*(m_pXValues[i]-m_fMinX);
631 break;
632 case ResetType::LINEAR_DESCENDING:
634 for( int i = 0; i < m_nValues; i++ )
636 m_pNewYValues[ i ] = m_fMaxY - (m_fMaxY-m_fMinY)/(m_fMaxX-m_fMinX)*(m_pXValues[i]-m_fMinX);
639 break;
640 case ResetType::RESET:
642 if( m_pOrigYValues && m_pNewYValues && m_nValues )
643 memcpy( m_pNewYValues.get(), m_pOrigYValues, m_nValues*sizeof(double) );
645 break;
646 case ResetType::EXPONENTIAL:
648 for( int i = 0; i < m_nValues; i++ )
650 m_pNewYValues[ i ] = m_fMinY + (m_fMaxY-m_fMinY)*(std::expm1((m_pXValues[i]-m_fMinX)/(m_fMaxX-m_fMinX)))/(M_E-1.0);
653 break;
655 default:
656 break;
659 if (m_pNewYValues)
661 for(size_t i(0); i < m_aHandles.size(); i++)
663 // find nearest xvalue
664 double x, y;
665 transform( m_aHandles[i].maPos, x, y );
666 int nIndex = 0;
667 double delta = std::fabs( x-m_pXValues[0] );
668 for( int n = 1; n < m_nValues; n++ )
670 if( delta > std::fabs( x - m_pXValues[ n ] ) )
672 delta = std::fabs( x - m_pXValues[ n ] );
673 nIndex = n;
676 if( 0 == i )
677 m_aHandles[i].maPos = transform( m_fMinX, m_pNewYValues[ nIndex ] );
678 else if( m_aHandles.size() - 1 == i )
679 m_aHandles[i].maPos = transform( m_fMaxX, m_pNewYValues[ nIndex ] );
680 else
681 m_aHandles[i].maPos = transform( m_pXValues[ nIndex ], m_pNewYValues[ nIndex ] );
685 Invalidate();
688 IMPL_LINK_NOARG(GridDialog, ClickButtonHdl, weld::Button&, void)
690 int nType = m_xResetTypeBox->get_active();
691 m_xGridWindow->ChangeMode(static_cast<ResetType>(nType));
694 double* GridDialog::getNewYValues()
696 return m_xGridWindow->getNewYValues();
699 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */