Bug Summary

File:home/maarten/src/libreoffice/core/extensions/source/scanner/grid.cxx
Warning:line 365, column 32
The left operand of '-' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name grid.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/extensions/inc -I /home/maarten/src/libreoffice/core/external/sane/inc -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/extensions/source/scanner/grid.cxx
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21#include <osl/thread.h>
22#include <cstdio>
23#include <math.h>
24#include <boost/math/special_functions/expm1.hpp>
25
26#include <bitmaps.hlst>
27#include <cmath>
28
29#include "grid.hxx"
30#include <vcl/bitmapex.hxx>
31#include <vcl/customweld.hxx>
32#include <vcl/event.hxx>
33#include <vcl/settings.hxx>
34#include <vcl/svapp.hxx>
35
36#include <algorithm>
37#include <limits>
38#include <memory>
39
40class GridWindow : public weld::CustomWidgetController
41{
42 // helper class for handles
43 struct impHandle
44 {
45 Point maPos;
46 sal_uInt16 mnOffX;
47 sal_uInt16 mnOffY;
48
49 impHandle(const Point& rPos, sal_uInt16 nX, sal_uInt16 nY)
50 : maPos(rPos), mnOffX(nX), mnOffY(nY)
51 {
52 }
53
54 bool operator<(const impHandle& rComp) const
55 {
56 return (maPos.X() < rComp.maPos.X());
57 }
58
59 void draw(vcl::RenderContext& rRenderContext, const BitmapEx& rBitmapEx)
60 {
61 const Point aOffset(rRenderContext.PixelToLogic(Point(mnOffX, mnOffY)));
62 rRenderContext.DrawBitmapEx(maPos - aOffset, rBitmapEx);
63 }
64
65 bool isHit(OutputDevice const & rWin, const Point& rPos)
66 {
67 const Point aOffset(rWin.PixelToLogic(Point(mnOffX, mnOffY)));
68 const tools::Rectangle aTarget(maPos - aOffset, maPos + aOffset);
69 return aTarget.IsInside(rPos);
70 }
71 };
72
73 tools::Rectangle m_aGridArea;
74
75 double m_fMinX;
76 double m_fMinY;
77 double m_fMaxX;
78 double m_fMaxY;
79
80 double m_fChunkX;
81 double m_fMinChunkX;
82 double m_fChunkY;
83 double m_fMinChunkY;
84
85 double* m_pXValues;
86 double* m_pOrigYValues;
87 int m_nValues;
88 std::unique_ptr<double[]> m_pNewYValues;
89
90 sal_uInt16 m_BmOffX;
91 sal_uInt16 m_BmOffY;
92
93 bool m_bCutValues;
94
95 // stuff for handles
96 using Handles = std::vector<impHandle>;
97 static constexpr auto npos = std::numeric_limits<Handles::size_type>::max();
98 Handles m_aHandles;
99 Handles::size_type m_nDragIndex;
100
101 BitmapEx m_aMarkerBitmap;
102
103 Point transform( double x, double y );
104 void transform( const Point& rOriginal, double& x, double& y );
105
106 double findMinX();
107 double findMinY();
108 double findMaxX();
109 double findMaxY();
110
111 void drawGrid(vcl::RenderContext& rRenderContext);
112 void drawOriginal(vcl::RenderContext& rRenderContext);
113 void drawNew(vcl::RenderContext& rRenderContext);
114 void drawHandles(vcl::RenderContext& rRenderContext);
115
116 void computeExtremes();
117 static void computeChunk( double fMin, double fMax, double& fChunkOut, double& fMinChunkOut );
118 void computeNew();
119 static double interpolate( double x, double const * pNodeX, double const * pNodeY, int nNodes );
120
121 virtual bool MouseMove( const MouseEvent& ) override;
122 virtual bool MouseButtonDown( const MouseEvent& ) override;
123 virtual bool MouseButtonUp( const MouseEvent& ) override;
124 void onResize();
125 virtual void Resize() override;
126 virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
127 void drawLine(vcl::RenderContext& rRenderContext, double x1, double y1, double x2, double y2);
128public:
129 GridWindow();
130 void Init(double* pXValues, double* pYValues, int nValues, bool bCutValues, const BitmapEx &rMarkerBitmap);
131 virtual ~GridWindow() override;
132
133 void setBoundings( double fMinX, double fMinY, double fMaxX, double fMaxY );
134
135 double* getNewYValues() { return m_pNewYValues.get(); }
136
137 void ChangeMode(ResetType nType);
138
139 virtual void Paint( vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect ) override;
140};
141
142GridWindow::GridWindow()
143 : m_aGridArea(50, 15, 100, 100)
144 , m_fMinX(0.0)
145 , m_fMinY(0.0)
146 , m_fMaxX(0.0)
147 , m_fMaxY(0.0)
148 , m_fChunkX(0.0)
149 , m_fMinChunkX(0.0)
150 , m_fChunkY(0.0)
151 , m_fMinChunkY(0.0)
152 , m_pXValues(nullptr)
153 , m_pOrigYValues(nullptr)
154 , m_nValues(0)
155 , m_BmOffX(0)
156 , m_BmOffY(0)
157 , m_bCutValues(false)
158 , m_aHandles()
159 , m_nDragIndex(npos)
160{
161}
162
163void GridWindow::Init(double* pXValues, double* pYValues, int nValues, bool bCutValues, const BitmapEx &rMarkerBitmap)
164{
165 m_aMarkerBitmap = rMarkerBitmap;
166 m_pXValues = pXValues;
167 m_pOrigYValues = pYValues;
168 m_nValues = nValues;
169 m_bCutValues = bCutValues;
170
171 onResize();
172
173 if (m_pOrigYValues && m_nValues)
174 {
175 m_pNewYValues.reset(new double[ m_nValues ]);
176 memcpy( m_pNewYValues.get(), m_pOrigYValues, sizeof( double ) * m_nValues );
177 }
178
179 setBoundings( 0, 0, 1023, 1023 );
180 computeExtremes();
181
182 // create left and right marker as first and last entry
183 m_BmOffX = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Width() >> 1);
184 m_BmOffY = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Height() >> 1);
185 m_aHandles.push_back(impHandle(transform(findMinX(), findMinY()), m_BmOffX, m_BmOffY));
186 m_aHandles.push_back(impHandle(transform(findMaxX(), findMaxY()), m_BmOffX, m_BmOffY));
187}
188
189void GridWindow::Resize()
190{
191 onResize();
192}
193
194void GridWindow::onResize()
195{
196 Size aSize = GetOutputSizePixel();
197 m_aGridArea.setWidth( aSize.Width() - 80 );
198 m_aGridArea.setHeight( aSize.Height() - 40 );
199}
200
201void GridWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
202{
203 Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(240, 200), MapMode(MapUnit::MapAppFont)));
204 pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
205 CustomWidgetController::SetDrawingArea(pDrawingArea);
206 SetOutputSizePixel(aSize);
207}
208
209GridDialog::GridDialog(weld::Window* pParent, double* pXValues, double* pYValues, int nValues)
210 : GenericDialogController(pParent, "modules/scanner/ui/griddialog.ui", "GridDialog")
211 , m_xOKButton(m_xBuilder->weld_button("ok"))
212 , m_xResetTypeBox(m_xBuilder->weld_combo_box("resetTypeCombobox"))
213 , m_xResetButton(m_xBuilder->weld_button("resetButton"))
214 , m_xGridWindow(new GridWindow)
215 , m_xGridWindowWND(new weld::CustomWeld(*m_xBuilder, "gridwindow", *m_xGridWindow))
216{
217 m_xGridWindow->Init(pXValues, pYValues, nValues, true/*bCutValues*/, BitmapEx(RID_SCANNER_HANDLE"extensions/res/scanner/handle.png"));
218 m_xResetTypeBox->set_active(0);
219 m_xResetButton->connect_clicked( LINK( this, GridDialog, ClickButtonHdl )::tools::detail::makeLink( ::tools::detail::castTo<GridDialog
*>(this), &GridDialog::LinkStubClickButtonHdl)
);
220}
221
222GridDialog::~GridDialog()
223{
224}
225
226GridWindow::~GridWindow()
227{
228 m_pNewYValues.reset();
229}
230
231double GridWindow::findMinX()
232{
233 if( ! m_pXValues )
234 return 0.0;
235 double fMin = m_pXValues[0];
236 for( int i = 1; i < m_nValues; i++ )
237 if( m_pXValues[ i ] < fMin )
238 fMin = m_pXValues[ i ];
239 return fMin;
240}
241
242double GridWindow::findMinY()
243{
244 if( ! m_pNewYValues )
245 return 0.0;
246 double fMin = m_pNewYValues[0];
247 for( int i = 1; i < m_nValues; i++ )
248 if( m_pNewYValues[ i ] < fMin )
249 fMin = m_pNewYValues[ i ];
250 return fMin;
251}
252
253
254double GridWindow::findMaxX()
255{
256 if( ! m_pXValues )
257 return 0.0;
258 double fMax = m_pXValues[0];
259 for( int i = 1; i < m_nValues; i++ )
260 if( m_pXValues[ i ] > fMax )
261 fMax = m_pXValues[ i ];
262 return fMax;
263}
264
265
266double GridWindow::findMaxY()
267{
268 if( ! m_pNewYValues )
269 return 0.0;
270 double fMax = m_pNewYValues[0];
271 for( int i = 1; i < m_nValues; i++ )
272 if( m_pNewYValues[ i ] > fMax )
273 fMax = m_pNewYValues[ i ];
274 return fMax;
275}
276
277
278void GridWindow::computeExtremes()
279{
280 if( !(m_nValues && m_pXValues && m_pOrigYValues) )
281 return;
282
283 m_fMaxX = m_fMinX = m_pXValues[0];
284 m_fMaxY = m_fMinY = m_pOrigYValues[0];
285 for( int i = 1; i < m_nValues; i++ )
286 {
287 if( m_pXValues[ i ] > m_fMaxX )
288 m_fMaxX = m_pXValues[ i ];
289 else if( m_pXValues[ i ] < m_fMinX )
290 m_fMinX = m_pXValues[ i ];
291 if( m_pOrigYValues[ i ] > m_fMaxY )
292 m_fMaxY = m_pOrigYValues[ i ];
293 else if( m_pOrigYValues[ i ] < m_fMinY )
294 m_fMinY = m_pOrigYValues[ i ];
295 }
296 setBoundings( m_fMinX, m_fMinY, m_fMaxX, m_fMaxY );
297}
298
299
300Point GridWindow::transform( double x, double y )
301{
302 Point aRet;
303
304 aRet.setX( static_cast<long>( ( x - m_fMinX ) *
305 static_cast<double>(m_aGridArea.GetWidth()) / ( m_fMaxX - m_fMinX )
306 + m_aGridArea.Left() ) );
307 aRet.setY( static_cast<long>(
308 m_aGridArea.Bottom() -
309 ( y - m_fMinY ) *
310 static_cast<double>(m_aGridArea.GetHeight()) / ( m_fMaxY - m_fMinY ) ) );
311 return aRet;
312}
313
314void GridWindow::transform( const Point& rOriginal, double& x, double& y )
315{
316 const long nWidth = m_aGridArea.GetWidth();
317 const long nHeight = m_aGridArea.GetHeight();
318 if (!nWidth
12.1
'nWidth' is 0
|| !nHeight)
319 return;
13
Returning without writing to 'y'
320 x = ( rOriginal.X() - m_aGridArea.Left() ) * (m_fMaxX - m_fMinX) / static_cast<double>(nWidth) + m_fMinX;
321 y = ( m_aGridArea.Bottom() - rOriginal.Y() ) * (m_fMaxY - m_fMinY) / static_cast<double>(nHeight) + m_fMinY;
322}
323
324void GridWindow::drawLine(vcl::RenderContext& rRenderContext, double x1, double y1, double x2, double y2 )
325{
326 rRenderContext.DrawLine(transform(x1, y1), transform(x2, y2));
327}
328
329void GridWindow::computeChunk( double fMin, double fMax, double& fChunkOut, double& fMinChunkOut )
330{
331 // get a nice chunk size like 10, 100, 25 or such
332 fChunkOut = ( fMax - fMin ) / 6.0;
333 int logchunk = static_cast<int>(std::log10( fChunkOut ));
334 int nChunk = static_cast<int>( fChunkOut / std::exp( static_cast<double>(logchunk-1) * M_LN102.30258509299404568402 ) );
335 if( nChunk >= 75 )
336 nChunk = 100;
337 else if( nChunk >= 35 )
338 nChunk = 50;
339 else if ( nChunk > 20 )
340 nChunk = 25;
341 else if ( nChunk >= 13 )
342 nChunk = 20;
343 else if( nChunk > 5 )
344 nChunk = 10;
345 else
346 nChunk = 5;
347 fChunkOut = static_cast<double>(nChunk) * exp( static_cast<double>(logchunk-1) * M_LN102.30258509299404568402 );
348 // compute whole chunks fitting into fMin
349 nChunk = static_cast<int>( fMin / fChunkOut );
350 fMinChunkOut = static_cast<double>(nChunk) * fChunkOut;
351 while( fMinChunkOut < fMin )
352 fMinChunkOut += fChunkOut;
353}
354
355
356void GridWindow::computeNew()
357{
358 if(2 == m_aHandles.size())
9
Assuming the condition is true
10
Taking true branch
359 {
360 // special case: only left and right markers
361 double xleft, yleft;
362 double xright, yright;
11
'yright' declared without an initial value
363 transform(m_aHandles[0].maPos, xleft, yleft);
364 transform(m_aHandles[1].maPos, xright, yright );
12
Calling 'GridWindow::transform'
14
Returning from 'GridWindow::transform'
365 double factor = (yright-yleft)/(xright-xleft);
15
The left operand of '-' is a garbage value
366 for( int i = 0; i < m_nValues; i++ )
367 {
368 m_pNewYValues[ i ] = yleft + ( m_pXValues[ i ] - xleft )*factor;
369 }
370 }
371 else
372 {
373 // sort markers
374 std::sort(m_aHandles.begin(), m_aHandles.end());
375 const int nSorted = m_aHandles.size();
376 int i;
377
378 // get node arrays
379 std::unique_ptr<double[]> nodex(new double[ nSorted ]);
380 std::unique_ptr<double[]> nodey(new double[ nSorted ]);
381
382 for( i = 0; i < nSorted; i++ )
383 transform( m_aHandles[i].maPos, nodex[ i ], nodey[ i ] );
384
385 for( i = 0; i < m_nValues; i++ )
386 {
387 double x = m_pXValues[ i ];
388 m_pNewYValues[ i ] = interpolate( x, nodex.get(), nodey.get(), nSorted );
389 if( m_bCutValues )
390 {
391 if( m_pNewYValues[ i ] > m_fMaxY )
392 m_pNewYValues[ i ] = m_fMaxY;
393 else if( m_pNewYValues[ i ] < m_fMinY )
394 m_pNewYValues[ i ] = m_fMinY;
395 }
396 }
397 }
398}
399
400
401double GridWindow::interpolate(
402 double x,
403 double const * pNodeX,
404 double const * pNodeY,
405 int nNodes )
406{
407 // compute Lagrange interpolation
408 double ret = 0;
409 for( int i = 0; i < nNodes; i++ )
410 {
411 double sum = pNodeY[ i ];
412 for( int n = 0; n < nNodes; n++ )
413 {
414 if( n != i )
415 {
416 sum *= x - pNodeX[ n ];
417 sum /= pNodeX[ i ] - pNodeX[ n ];
418 }
419 }
420 ret += sum;
421 }
422 return ret;
423}
424
425void GridDialog::setBoundings(double fMinX, double fMinY, double fMaxX, double fMaxY)
426{
427 m_xGridWindow->setBoundings(fMinX, fMinY, fMaxX, fMaxY);
428}
429
430void GridWindow::setBoundings(double fMinX, double fMinY, double fMaxX, double fMaxY)
431{
432 m_fMinX = fMinX;
433 m_fMinY = fMinY;
434 m_fMaxX = fMaxX;
435 m_fMaxY = fMaxY;
436
437 computeChunk( m_fMinX, m_fMaxX, m_fChunkX, m_fMinChunkX );
438 computeChunk( m_fMinY, m_fMaxY, m_fChunkY, m_fMinChunkY );
439}
440
441void GridWindow::drawGrid(vcl::RenderContext& rRenderContext)
442{
443 char pBuf[256];
444 rRenderContext.SetLineColor(COL_BLACK);
445 // draw vertical lines
446 for (double fX = m_fMinChunkX; fX < m_fMaxX; fX += m_fChunkX)
447 {
448 drawLine(rRenderContext, fX, m_fMinY, fX, m_fMaxY);
449 // draw tickmarks
450 Point aPt = transform(fX, m_fMinY);
451 std::sprintf(pBuf, "%g", fX);
452 OUString aMark(pBuf, strlen(pBuf), osl_getThreadTextEncoding());
453 Size aTextSize(rRenderContext.GetTextWidth(aMark), rRenderContext.GetTextHeight());
454 aPt.AdjustX( -(aTextSize.Width() / 2) );
455 aPt.AdjustY(aTextSize.Height() / 2 );
456 rRenderContext.DrawText(aPt, aMark);
457 }
458 // draw horizontal lines
459 for (double fY = m_fMinChunkY; fY < m_fMaxY; fY += m_fChunkY)
460 {
461 drawLine(rRenderContext, m_fMinX, fY, m_fMaxX, fY);
462 // draw tickmarks
463 Point aPt = transform(m_fMinX, fY);
464 std::sprintf(pBuf, "%g", fY);
465 OUString aMark(pBuf, strlen(pBuf), osl_getThreadTextEncoding());
466 Size aTextSize(rRenderContext.GetTextWidth(aMark), rRenderContext.GetTextHeight());
467 aPt.AdjustX( -(aTextSize.Width() + 2) );
468 aPt.AdjustY( -(aTextSize.Height() / 2) );
469 rRenderContext.DrawText(aPt, aMark);
470 }
471
472 // draw boundings
473 drawLine(rRenderContext, m_fMinX, m_fMinY, m_fMaxX, m_fMinY);
474 drawLine(rRenderContext, m_fMinX, m_fMaxY, m_fMaxX, m_fMaxY);
475 drawLine(rRenderContext, m_fMinX, m_fMinY, m_fMinX, m_fMaxY);
476 drawLine(rRenderContext, m_fMaxX, m_fMinY, m_fMaxX, m_fMaxY);
477}
478
479void GridWindow::drawOriginal(vcl::RenderContext& rRenderContext)
480{
481 if (m_nValues && m_pXValues && m_pOrigYValues)
482 {
483 rRenderContext.SetLineColor(COL_RED);
484 for (int i = 0; i < m_nValues - 1; i++)
485 {
486 drawLine(rRenderContext,
487 m_pXValues[i], m_pOrigYValues[i],
488 m_pXValues[i + 1], m_pOrigYValues[i + 1]);
489 }
490 }
491}
492
493void GridWindow::drawNew(vcl::RenderContext& rRenderContext)
494{
495 if (m_nValues && m_pXValues && m_pNewYValues)
496 {
497 rRenderContext.SetClipRegion(vcl::Region(m_aGridArea));
498 rRenderContext.SetLineColor(COL_YELLOW);
499 for (int i = 0; i < m_nValues - 1; i++)
500 {
501 drawLine(rRenderContext,
502 m_pXValues[i], m_pNewYValues[i],
503 m_pXValues[i + 1], m_pNewYValues[i + 1]);
504 }
505 rRenderContext.SetClipRegion();
506 }
507}
508
509void GridWindow::drawHandles(vcl::RenderContext& rRenderContext)
510{
511 for(impHandle & rHandle : m_aHandles)
512 {
513 rHandle.draw(rRenderContext, m_aMarkerBitmap);
514 }
515}
516
517void GridWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
518{
519 rRenderContext.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetDialogColor()));
520 drawGrid(rRenderContext);
521 drawOriginal(rRenderContext);
522 drawNew(rRenderContext);
523 drawHandles(rRenderContext);
524}
525
526bool GridWindow::MouseMove( const MouseEvent& rEvt )
527{
528 if( rEvt.GetButtons() == MOUSE_LEFT(sal_uInt16(0x0001)) && m_nDragIndex != npos )
529 {
530 Point aPoint( rEvt.GetPosPixel() );
531
532 if( m_nDragIndex == 0 || m_nDragIndex == m_aHandles.size() - 1)
533 {
534 aPoint.setX( m_aHandles[m_nDragIndex].maPos.X() );
535 }
536 else
537 {
538 if(aPoint.X() < m_aGridArea.Left())
539 aPoint.setX( m_aGridArea.Left() );
540 else if(aPoint.X() > m_aGridArea.Right())
541 aPoint.setX( m_aGridArea.Right() );
542 }
543
544 if( aPoint.Y() < m_aGridArea.Top() )
545 aPoint.setY( m_aGridArea.Top() );
546 else if( aPoint.Y() > m_aGridArea.Bottom() )
547 aPoint.setY( m_aGridArea.Bottom() );
548
549 if( aPoint != m_aHandles[m_nDragIndex].maPos )
550 {
551 m_aHandles[m_nDragIndex].maPos = aPoint;
552 Invalidate( m_aGridArea );
553 }
554 }
555
556 return false;
557}
558
559bool GridWindow::MouseButtonUp( const MouseEvent& rEvt )
560{
561 if( rEvt.GetButtons() == MOUSE_LEFT(sal_uInt16(0x0001)) )
562 {
563 if( m_nDragIndex != npos )
564 {
565 m_nDragIndex = npos;
566 computeNew();
567 Invalidate(m_aGridArea);
568 }
569 }
570
571 return false;
572}
573
574bool GridWindow::MouseButtonDown( const MouseEvent& rEvt )
575{
576 Point aPoint( rEvt.GetPosPixel() );
577 Handles::size_type nMarkerIndex = npos;
578
579 for(Handles::size_type a(0); nMarkerIndex
0.1
'nMarkerIndex' is equal to 'npos'
== npos && a < m_aHandles.size(); a++)
1
Assuming the condition is false
2
Loop condition is false. Execution continues on line 587
580 {
581 if(m_aHandles[a].isHit(GetDrawingArea()->get_ref_device(), aPoint))
582 {
583 nMarkerIndex = a;
584 }
585 }
586
587 if( rEvt.GetButtons() == MOUSE_LEFT(sal_uInt16(0x0001)) )
3
Assuming the condition is false
4
Taking false branch
588 {
589 // user wants to drag a button
590 if( nMarkerIndex != npos )
591 {
592 m_nDragIndex = nMarkerIndex;
593 }
594 }
595 else if( rEvt.GetButtons() == MOUSE_RIGHT(sal_uInt16(0x0004)) )
5
Assuming the condition is true
6
Taking true branch
596 {
597 // user wants to add/delete a button
598 if( nMarkerIndex
6.1
'nMarkerIndex' is equal to 'npos'
!= npos )
7
Taking false branch
599 {
600 if( nMarkerIndex != 0 && nMarkerIndex != m_aHandles.size() - 1)
601 {
602 // delete marker under mouse
603 if( m_nDragIndex == nMarkerIndex )
604 m_nDragIndex = npos;
605
606 m_aHandles.erase(m_aHandles.begin() + nMarkerIndex);
607 }
608 }
609 else
610 {
611 m_BmOffX = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Width() >> 1);
612 m_BmOffY = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Height() >> 1);
613 m_aHandles.push_back(impHandle(aPoint, m_BmOffX, m_BmOffY));
614 }
615
616 computeNew();
8
Calling 'GridWindow::computeNew'
617 Invalidate(m_aGridArea);
618 }
619
620 return false;
621}
622
623void GridWindow::ChangeMode(ResetType nType)
624{
625 switch( nType )
626 {
627 case ResetType::LINEAR_ASCENDING:
628 {
629 for( int i = 0; i < m_nValues; i++ )
630 {
631 m_pNewYValues[ i ] = m_fMinY + (m_fMaxY-m_fMinY)/(m_fMaxX-m_fMinX)*(m_pXValues[i]-m_fMinX);
632 }
633 }
634 break;
635 case ResetType::LINEAR_DESCENDING:
636 {
637 for( int i = 0; i < m_nValues; i++ )
638 {
639 m_pNewYValues[ i ] = m_fMaxY - (m_fMaxY-m_fMinY)/(m_fMaxX-m_fMinX)*(m_pXValues[i]-m_fMinX);
640 }
641 }
642 break;
643 case ResetType::RESET:
644 {
645 if( m_pOrigYValues && m_pNewYValues && m_nValues )
646 memcpy( m_pNewYValues.get(), m_pOrigYValues, m_nValues*sizeof(double) );
647 }
648 break;
649 case ResetType::EXPONENTIAL:
650 {
651 for( int i = 0; i < m_nValues; i++ )
652 {
653 m_pNewYValues[ i ] = m_fMinY + (m_fMaxY-m_fMinY)*(boost::math::expm1((m_pXValues[i]-m_fMinX)/(m_fMaxX-m_fMinX)))/(M_E2.7182818284590452354-1.0);
654 }
655 }
656 break;
657
658 default:
659 break;
660 }
661
662 if (m_pNewYValues)
663 {
664 for(size_t i(0); i < m_aHandles.size(); i++)
665 {
666 // find nearest xvalue
667 double x, y;
668 transform( m_aHandles[i].maPos, x, y );
669 int nIndex = 0;
670 double delta = std::fabs( x-m_pXValues[0] );
671 for( int n = 1; n < m_nValues; n++ )
672 {
673 if( delta > std::fabs( x - m_pXValues[ n ] ) )
674 {
675 delta = std::fabs( x - m_pXValues[ n ] );
676 nIndex = n;
677 }
678 }
679 if( 0 == i )
680 m_aHandles[i].maPos = transform( m_fMinX, m_pNewYValues[ nIndex ] );
681 else if( m_aHandles.size() - 1 == i )
682 m_aHandles[i].maPos = transform( m_fMaxX, m_pNewYValues[ nIndex ] );
683 else
684 m_aHandles[i].maPos = transform( m_pXValues[ nIndex ], m_pNewYValues[ nIndex ] );
685 }
686 }
687
688 Invalidate();
689}
690
691IMPL_LINK_NOARG(GridDialog, ClickButtonHdl, weld::Button&, void)void GridDialog::LinkStubClickButtonHdl(void * instance, weld
::Button& data) { return static_cast<GridDialog *>(
instance)->ClickButtonHdl(data); } void GridDialog::ClickButtonHdl
(__attribute__ ((unused)) weld::Button&)
692{
693 int nType = m_xResetTypeBox->get_active();
694 m_xGridWindow->ChangeMode(static_cast<ResetType>(nType));
695}
696
697double* GridDialog::getNewYValues()
698{
699 return m_xGridWindow->getNewYValues();
700}
701
702/* vim:set shiftwidth=4 softtabstop=4 expandtab: */