bump product version to 5.0.4.1
[LibreOffice.git] / extensions / source / scanner / sanedlg.cxx
blob0aee63fdc57d16274d9c3d304b94e9e954294eae
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 <stdio.h>
21 #include <stdlib.h>
22 #include <tools/config.hxx>
23 #include <vcl/dibtools.hxx>
24 #include <vcl/layout.hxx>
25 #include <vcl/builderfactory.hxx>
26 #include <sanedlg.hxx>
27 #include <grid.hxx>
28 #include <math.h>
29 #include <sal/macros.h>
30 #include <rtl/strbuf.hxx>
31 #include <boost/scoped_array.hpp>
32 #include "strings.hrc"
34 #define PREVIEW_WIDTH 113
35 #define PREVIEW_HEIGHT 160
37 #define RECT_SIZE_PIX 7
39 namespace {
41 void DrawRectangles(vcl::RenderContext& rRenderContext, Point& rUL, Point& rBR)
43 int nMiddleX, nMiddleY;
44 Point aBL, aUR;
46 aUR = Point(rBR.X(), rUL.Y());
47 aBL = Point(rUL.X(), rBR.Y());
48 nMiddleX = (rBR.X() - rUL.X()) / 2 + rUL.X();
49 nMiddleY = (rBR.Y() - rUL.Y()) / 2 + rUL.Y();
51 rRenderContext.DrawLine(rUL, aBL);
52 rRenderContext.DrawLine(aBL, rBR);
53 rRenderContext.DrawLine(rBR, aUR);
54 rRenderContext.DrawLine(aUR, rUL);
55 rRenderContext.DrawRect(Rectangle(rUL, Size(RECT_SIZE_PIX,RECT_SIZE_PIX)));
56 rRenderContext.DrawRect(Rectangle(aBL, Size(RECT_SIZE_PIX, -RECT_SIZE_PIX)));
57 rRenderContext.DrawRect(Rectangle(rBR, Size(-RECT_SIZE_PIX, -RECT_SIZE_PIX)));
58 rRenderContext.DrawRect(Rectangle(aUR, Size(-RECT_SIZE_PIX, RECT_SIZE_PIX )));
59 rRenderContext.DrawRect(Rectangle(Point(nMiddleX - RECT_SIZE_PIX / 2, rUL.Y()), Size(RECT_SIZE_PIX, RECT_SIZE_PIX)));
60 rRenderContext.DrawRect(Rectangle(Point(nMiddleX - RECT_SIZE_PIX / 2, rBR.Y()), Size(RECT_SIZE_PIX, -RECT_SIZE_PIX)));
61 rRenderContext.DrawRect(Rectangle(Point(rUL.X(), nMiddleY - RECT_SIZE_PIX / 2), Size(RECT_SIZE_PIX, RECT_SIZE_PIX)));
62 rRenderContext.DrawRect(Rectangle(Point(rBR.X(), nMiddleY - RECT_SIZE_PIX / 2), Size(-RECT_SIZE_PIX, RECT_SIZE_PIX)));
67 class ScanPreview : public vcl::Window
69 private:
70 enum DragDirection { TopLeft, Top, TopRight, Right, BottomRight, Bottom,
71 BottomLeft, Left };
73 Bitmap maPreviewBitmap;
74 Rectangle maPreviewRect;
75 Point maTopLeft, maBottomRight;
76 Point maMinTopLeft, maMaxBottomRight;
77 VclPtr<SaneDlg> mpParentDialog;
78 DragDirection meDragDirection;
79 bool mbDragEnable;
80 bool mbDragDrawn;
81 bool mbIsDragging;
83 public:
84 ScanPreview(vcl::Window* pParent, WinBits nStyle)
85 : Window(pParent, nStyle)
86 , maMaxBottomRight(PREVIEW_WIDTH, PREVIEW_HEIGHT)
87 , mpParentDialog(NULL)
88 , meDragDirection(TopLeft)
89 , mbDragEnable(false)
90 , mbDragDrawn(false)
91 , mbIsDragging(false)
95 virtual ~ScanPreview()
97 disposeOnce();
100 virtual void dispose() SAL_OVERRIDE
102 mpParentDialog.clear();
103 vcl::Window::dispose();
106 void Init(SaneDlg *pParent)
108 mpParentDialog = pParent;
111 void ResetForNewScanner()
113 maTopLeft = Point();
114 maBottomRight = Point();
115 maMinTopLeft = Point();
116 maMaxBottomRight = Point(PREVIEW_WIDTH, PREVIEW_HEIGHT);
119 void EnableDrag()
121 mbDragEnable = true;
123 void DisableDrag()
125 mbDragEnable = false;
127 bool IsDragEnabled()
129 return mbDragEnable;
132 virtual void Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect) SAL_OVERRIDE;
133 virtual void MouseButtonDown(const MouseEvent& rMEvt) SAL_OVERRIDE;
134 virtual void MouseMove(const MouseEvent& rMEvt) SAL_OVERRIDE;
135 virtual void MouseButtonUp(const MouseEvent& rMEvt) SAL_OVERRIDE;
136 Point GetPixelPos(const Point& rIn) const;
137 Point GetLogicPos(const Point& rIn) const;
139 void GetPreviewLogicRect(Point& rTopLeft, Point &rBottomRight) const
141 rTopLeft = GetLogicPos(maTopLeft);
142 rBottomRight = GetLogicPos(maBottomRight);
144 void GetMaxLogicRect(Point& rTopLeft, Point &rBottomRight) const
146 rTopLeft = maMinTopLeft;
147 rBottomRight = maMaxBottomRight;
150 void ChangePreviewLogicTopLeftY(long Y)
152 Point aPoint(0, Y);
153 aPoint = GetPixelPos(aPoint);
154 maTopLeft.Y() = aPoint.Y();
156 void ChangePreviewLogicTopLeftX(long X)
158 Point aPoint(X, 0);
159 aPoint = GetPixelPos(aPoint);
160 maTopLeft.X() = aPoint.X();
162 void ChangePreviewLogicBottomRightY(long Y)
164 Point aPoint(0, Y);
165 aPoint = GetPixelPos(aPoint);
166 maBottomRight.Y() = aPoint.Y();
168 void ChangePreviewLogicBottomRightX(long X)
170 Point aPoint(X, 0);
171 aPoint = GetPixelPos(aPoint);
172 maBottomRight.X() = aPoint.X();
174 void SetPreviewLogicRect(const Point& rTopLeft, const Point &rBottomRight)
176 maTopLeft = GetPixelPos(rTopLeft);
177 maBottomRight = GetPixelPos(rBottomRight);
178 maPreviewRect = Rectangle(maTopLeft,
179 Size(maBottomRight.X() - maTopLeft.X(),
180 maBottomRight.Y() - maTopLeft.Y()));
182 void SetPreviewMaxRect(const Point& rTopLeft, const Point &rBottomRight)
184 maMinTopLeft = rTopLeft;
185 maMaxBottomRight = rBottomRight;
187 void DrawDrag(vcl::RenderContext& rRenderContext);
188 void UpdatePreviewBounds();
189 void SetBitmap(SvStream &rStream)
191 ReadDIB(maPreviewBitmap, rStream, true);
193 virtual Size GetOptimalSize() const SAL_OVERRIDE
195 Size aSize(LogicToPixel(Size(PREVIEW_WIDTH, PREVIEW_HEIGHT), MAP_APPFONT));
196 aSize.setWidth(aSize.getWidth()+1);
197 aSize.setHeight(aSize.getHeight()+1);
198 return aSize;
202 VCL_BUILDER_DECL_FACTORY(ScanPreview)
204 WinBits nWinStyle = 0;
205 OString sBorder = VclBuilder::extractCustomProperty(rMap);
206 if (!sBorder.isEmpty())
207 nWinStyle |= WB_BORDER;
208 rRet = VclPtr<ScanPreview>::Create(pParent, nWinStyle);
211 SaneDlg::SaneDlg( vcl::Window* pParent, Sane& rSane, bool bScanEnabled ) :
212 ModalDialog(pParent, "SaneDialog", "modules/scanner/ui/sanedialog.ui"),
213 mrSane( rSane ),
214 mbScanEnabled( bScanEnabled ),
215 mnCurrentOption(0),
216 mnCurrentElement(0),
217 mpRange(0),
218 mfMin(0.0),
219 mfMax(0.0),
220 doScan(false)
222 get(mpOKButton, "ok");
223 get(mpCancelButton, "cancel");
224 get(mpDeviceInfoButton, "deviceInfoButton");
225 get(mpPreviewButton, "previewButton");
226 get(mpScanButton, "scanButton");
227 get(mpButtonOption, "optionsButton");
228 get(mpOptionTitle, "optionTitleLabel");
229 Size aSize(LogicToPixel(Size(130, 102), MAP_APPFONT));
230 mpOptionTitle->set_width_request(aSize.Width());
231 mpOptionTitle->set_height_request(aSize.Height() / 2);
232 get(mpOptionDescTxt, "optionsDescLabel");
233 get(mpVectorTxt, "vectorLabel");
234 get(mpLeftField, "leftSpinbutton");
235 get(mpTopField, "topSpinbutton");
236 get(mpRightField, "rightSpinbutton");
237 get(mpBottomField, "bottomSpinbutton");
238 get(mpDeviceBox, "deviceCombobox");
239 get(mpReslBox, "reslCombobox");
240 get(mpAdvancedBox, "advancedCheckbutton");
241 get(mpVectorBox, "vectorSpinbutton-nospin");
242 get(mpQuantumRangeBox, "quantumRangeCombobox");
243 get(mpStringRangeBox, "stringRangeCombobox");
244 get(mpStringEdit, "stringEntry");
245 get(mpNumericEdit, "numericEntry");
246 get(mpOptionBox, "optionSvTreeListBox");
247 mpOptionBox->set_width_request(aSize.Width());
248 mpOptionBox->set_height_request(aSize.Height());
249 get(mpBoolCheckBox, "boolCheckbutton");
250 get(mpPreview, "preview");
251 mpPreview->Init(this);
252 if( Sane::IsSane() )
254 InitDevices(); // opens first sane device
255 DisableOption();
256 InitFields();
259 mpDeviceInfoButton->SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) );
260 mpPreviewButton->SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) );
261 mpScanButton->SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) );
262 mpButtonOption->SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) );
263 mpDeviceBox->SetSelectHdl( LINK( this, SaneDlg, SelectHdl ) );
264 mpOptionBox->SetSelectHdl( LINK( this, SaneDlg, OptionsBoxSelectHdl ) );
265 mpOKButton->SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) );
266 mpCancelButton->SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) );
267 mpBoolCheckBox->SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) );
268 mpStringEdit->SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
269 mpNumericEdit->SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
270 mpVectorBox->SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
271 mpReslBox->SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
272 mpStringRangeBox->SetSelectHdl( LINK( this, SaneDlg, SelectHdl ) );
273 mpQuantumRangeBox->SetSelectHdl( LINK( this, SaneDlg, SelectHdl ) );
274 mpLeftField->SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
275 mpRightField->SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
276 mpTopField->SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
277 mpBottomField->SetModifyHdl( LINK( this, SaneDlg, ModifyHdl ) );
278 mpAdvancedBox->SetClickHdl( LINK( this, SaneDlg, ClickBtnHdl ) );
280 maOldLink = mrSane.SetReloadOptionsHdl( LINK( this, SaneDlg, ReloadSaneOptionsHdl ) );
282 mpOptionBox->SetNodeBitmaps(get<FixedImage>("plus")->GetImage(),
283 get<FixedImage>("minus")->GetImage());
284 mpOptionBox->SetStyle(mpOptionBox->GetStyle() |
285 WB_HASLINES | WB_HASBUTTONS | WB_NOINITIALSELECTION |
286 WB_HASBUTTONSATROOT | WB_HASLINESATROOT);
289 SaneDlg::~SaneDlg()
291 disposeOnce();
294 void SaneDlg::dispose()
296 mrSane.SetReloadOptionsHdl(maOldLink);
297 mpOKButton.clear();
298 mpCancelButton.clear();
299 mpDeviceInfoButton.clear();
300 mpPreviewButton.clear();
301 mpScanButton.clear();
302 mpButtonOption.clear();
303 mpOptionTitle.clear();
304 mpOptionDescTxt.clear();
305 mpVectorTxt.clear();
306 mpLeftField.clear();
307 mpTopField.clear();
308 mpRightField.clear();
309 mpBottomField.clear();
310 mpDeviceBox.clear();
311 mpReslBox.clear();
312 mpAdvancedBox.clear();
313 mpVectorBox.clear();
314 mpQuantumRangeBox.clear();
315 mpStringRangeBox.clear();
316 mpBoolCheckBox.clear();
317 mpStringEdit.clear();
318 mpNumericEdit.clear();
319 mpOptionBox.clear();
320 mpPreview.clear();
321 ModalDialog::dispose();
324 namespace {
326 ResId SaneResId( sal_uInt32 nID )
328 static ResMgr* pResMgr = ResMgr::CreateResMgr( "scn" );
329 return ResId( nID, *pResMgr );
334 short SaneDlg::Execute()
336 if( ! Sane::IsSane() )
338 ScopedVclPtrInstance< MessageDialog > aErrorBox(nullptr, SaneResId(STR_COULD_NOT_BE_INIT));
339 aErrorBox->Execute();
340 return RET_CANCEL;
342 LoadState();
343 return ModalDialog::Execute();
346 void SaneDlg::InitDevices()
348 if( ! Sane::IsSane() )
349 return;
351 if( mrSane.IsOpen() )
352 mrSane.Close();
353 mrSane.ReloadDevices();
354 mpDeviceBox->Clear();
355 for (int i = 0; i < Sane::CountDevices(); ++i)
356 mpDeviceBox->InsertEntry(Sane::GetName(i));
357 if( Sane::CountDevices() )
359 mrSane.Open(0);
360 mpDeviceBox->SelectEntryPos(0);
364 void SaneDlg::InitFields()
366 if( ! Sane::IsSane() )
367 return;
369 int nOption, i, nValue;
370 double fValue;
371 bool bSuccess = false;
372 const char *ppSpecialOptions[] = {
373 "resolution",
374 "tl-x",
375 "tl-y",
376 "br-x",
377 "br-y",
378 "preview"
381 mpPreview->EnableDrag();
382 mpReslBox->Clear();
383 Point aTopLeft, aBottomRight;
384 mpPreview->GetPreviewLogicRect(aTopLeft, aBottomRight);
385 Point aMinTopLeft, aMaxBottomRight;
386 mpPreview->GetMaxLogicRect(aMinTopLeft, aMaxBottomRight);
387 mpScanButton->Show( mbScanEnabled );
389 if( ! mrSane.IsOpen() )
390 return;
392 // set Resolution
393 nOption = mrSane.GetOptionByName( "resolution" );
394 if( nOption != -1 )
396 double fRes;
398 bSuccess = mrSane.GetOptionValue( nOption, fRes );
399 if( bSuccess )
401 mpReslBox->Enable( true );
403 mpReslBox->SetValue( (long)fRes );
404 double *pDouble = NULL;
405 nValue = mrSane.GetRange( nOption, pDouble );
406 if( nValue > -1 )
408 if( nValue )
410 mpReslBox->SetMin( (long)pDouble[0] );
411 mpReslBox->SetMax( (long)pDouble[ nValue-1 ] );
412 for( i=0; i<nValue; i++ )
414 if( i == 0 || i == nValue-1 || ! ( ((int)pDouble[i]) % 20) )
415 mpReslBox->InsertValue( (long)pDouble[i] );
418 else
420 mpReslBox->SetMin( (long)pDouble[0] );
421 mpReslBox->SetMax( (long)pDouble[1] );
422 mpReslBox->InsertValue( (long)pDouble[0] );
423 // Can only select 75 and 2400 dpi in Scanner dialogue
424 // scanner allows random setting of dpi resolution, a slider might be useful
425 // support that
426 // workaround: offer at least some more standard dpi resolution between
427 // min and max value
428 int bGot300 = 0;
429 for ( int nRes = (long) pDouble[0] * 2; nRes < (long) pDouble[1]; nRes = nRes * 2 )
431 if ( !bGot300 && nRes > 300 ) {
432 nRes = 300; bGot300 = 1;
434 mpReslBox->InsertValue(nRes);
436 mpReslBox->InsertValue( (long)pDouble[1] );
439 else
440 mpReslBox->Enable( false );
441 delete [] pDouble;
444 else
445 mpReslBox->Enable( false );
447 // set scan area
448 for( i = 0; i < 4; i++ )
450 char const *pOptionName = NULL;
451 MetricField* pField = NULL;
452 switch( i )
454 case 0:
455 pOptionName = "tl-x";
456 pField = mpLeftField;
457 break;
458 case 1:
459 pOptionName = "tl-y";
460 pField = mpTopField;
461 break;
462 case 2:
463 pOptionName = "br-x";
464 pField = mpRightField;
465 break;
466 case 3:
467 pOptionName = "br-y";
468 pField = mpBottomField;
470 nOption = pOptionName ? mrSane.GetOptionByName( pOptionName ) : -1;
471 bSuccess = false;
472 if( nOption != -1 )
474 bSuccess = mrSane.GetOptionValue( nOption, fValue, 0 );
475 if( bSuccess )
477 if( mrSane.GetOptionUnit( nOption ) == SANE_UNIT_MM )
479 pField->SetUnit( FUNIT_MM );
480 pField->SetValue( (int)fValue, FUNIT_MM );
482 else // SANE_UNIT_PIXEL
484 pField->SetValue( (int)fValue, FUNIT_CUSTOM );
485 pField->SetCustomUnitText(OUString("Pixel"));
487 switch( i ) {
488 case 0: aTopLeft.X() = (int)fValue;break;
489 case 1: aTopLeft.Y() = (int)fValue;break;
490 case 2: aBottomRight.X() = (int)fValue;break;
491 case 3: aBottomRight.Y() = (int)fValue;break;
494 double *pDouble = NULL;
495 nValue = mrSane.GetRange( nOption, pDouble );
496 if( nValue > -1 )
498 if( pDouble )
500 pField->SetMin( (long)pDouble[0] );
501 if( nValue )
502 pField->SetMax( (long)pDouble[ nValue-1 ] );
503 else
504 pField->SetMax( (long)pDouble[ 1 ] );
505 delete [] pDouble;
507 switch( i ) {
508 case 0: aMinTopLeft.X() = pField->GetMin();break;
509 case 1: aMinTopLeft.Y() = pField->GetMin();break;
510 case 2: aMaxBottomRight.X() = pField->GetMax();break;
511 case 3: aMaxBottomRight.Y() = pField->GetMax();break;
514 else
516 switch( i ) {
517 case 0: aMinTopLeft.X() = (int)fValue;break;
518 case 1: aMinTopLeft.Y() = (int)fValue;break;
519 case 2: aMaxBottomRight.X() = (int)fValue;break;
520 case 3: aMaxBottomRight.Y() = (int)fValue;break;
523 pField->Enable( true );
525 else
527 mpPreview->DisableDrag();
528 pField->SetMin( 0 );
529 switch( i ) {
530 case 0:
531 aMinTopLeft.X() = 0;
532 aTopLeft.X() = 0;
533 pField->SetMax( PREVIEW_WIDTH );
534 pField->SetValue( 0 );
535 break;
536 case 1:
537 aMinTopLeft.Y() = 0;
538 aTopLeft.Y() = 0;
539 pField->SetMax( PREVIEW_HEIGHT );
540 pField->SetValue( 0 );
541 break;
542 case 2:
543 aMaxBottomRight.X() = PREVIEW_WIDTH;
544 aBottomRight.X() = PREVIEW_WIDTH;
545 pField->SetMax( PREVIEW_WIDTH );
546 pField->SetValue( PREVIEW_WIDTH );
547 break;
548 case 3:
549 aMaxBottomRight.Y() = PREVIEW_HEIGHT;
550 aBottomRight.Y() = PREVIEW_HEIGHT;
551 pField->SetMax( PREVIEW_HEIGHT );
552 pField->SetValue( PREVIEW_HEIGHT );
553 break;
555 pField->Enable( false );
559 mpPreview->SetPreviewMaxRect(aMinTopLeft, aMaxBottomRight);
560 mpPreview->SetPreviewLogicRect(aTopLeft, aBottomRight);
561 mpPreview->Invalidate();
563 // fill OptionBox
564 mpOptionBox->Clear();
565 SvTreeListEntry* pParentEntry = 0;
566 bool bGroupRejected = false;
567 for( i = 1; i < mrSane.CountOptions(); i++ )
569 OUString aOption=mrSane.GetOptionName( i );
570 bool bInsertAdvanced =
571 (mrSane.GetOptionCap( i ) & SANE_CAP_ADVANCED) == 0 ||
572 mpAdvancedBox->IsChecked();
573 if( mrSane.GetOptionType( i ) == SANE_TYPE_GROUP )
575 if( bInsertAdvanced )
577 aOption = mrSane.GetOptionTitle( i );
578 pParentEntry = mpOptionBox->InsertEntry( aOption );
579 bGroupRejected = false;
581 else
582 bGroupRejected = true;
584 else if( !aOption.isEmpty() &&
585 ! ( mrSane.GetOptionCap( i ) &
587 SANE_CAP_HARD_SELECT |
588 SANE_CAP_INACTIVE
589 ) ) &&
590 bInsertAdvanced && ! bGroupRejected )
592 bool bIsSpecial = false;
593 for( size_t n = 0; !bIsSpecial &&
594 n < SAL_N_ELEMENTS(ppSpecialOptions); n++ )
596 if( aOption == OUString::createFromAscii(ppSpecialOptions[n]) )
597 bIsSpecial=true;
599 if( ! bIsSpecial )
601 if( pParentEntry )
602 mpOptionBox->InsertEntry( aOption, pParentEntry );
603 else
604 mpOptionBox->InsertEntry( aOption );
610 IMPL_LINK( SaneDlg, ClickBtnHdl, Button*, pButton )
612 if( mrSane.IsOpen() )
614 if( pButton == mpDeviceInfoButton )
616 OUString aString(SaneResId(STR_DEVICE_DESC));
617 aString = aString.replaceFirst( "%s", Sane::GetName( mrSane.GetDeviceNumber() ) );
618 aString = aString.replaceFirst( "%s", Sane::GetVendor( mrSane.GetDeviceNumber() ) );
619 aString = aString.replaceFirst( "%s", Sane::GetModel( mrSane.GetDeviceNumber() ) );
620 aString = aString.replaceFirst( "%s", Sane::GetType( mrSane.GetDeviceNumber() ) );
621 ScopedVclPtrInstance< MessageDialog > aInfoBox(this, aString, VCL_MESSAGE_INFO);
622 aInfoBox->Execute();
624 else if( pButton == mpPreviewButton )
625 AcquirePreview();
626 else if( pButton == mpBoolCheckBox )
628 mrSane.SetOptionValue( mnCurrentOption,
629 mpBoolCheckBox->IsChecked() );
631 else if( pButton == mpButtonOption )
634 SANE_Value_Type nType = mrSane.GetOptionType( mnCurrentOption );
635 switch( nType )
637 case SANE_TYPE_BUTTON:
638 mrSane.ActivateButtonOption( mnCurrentOption );
639 break;
640 case SANE_TYPE_FIXED:
641 case SANE_TYPE_INT:
643 int nElements = mrSane.GetOptionElements( mnCurrentOption );
644 boost::scoped_array<double> x(new double[ nElements ]);
645 boost::scoped_array<double> y(new double[ nElements ]);
646 for( int i = 0; i < nElements; i++ )
647 x[ i ] = (double)i;
648 mrSane.GetOptionValue( mnCurrentOption, y.get() );
650 ScopedVclPtrInstance< GridDialog > aGrid( x.get(), y.get(), nElements, this );
651 aGrid->SetText( mrSane.GetOptionName( mnCurrentOption ) );
652 aGrid->setBoundings( 0, mfMin, nElements, mfMax );
653 if( aGrid->Execute() && aGrid->getNewYValues() )
654 mrSane.SetOptionValue( mnCurrentOption, aGrid->getNewYValues() );
656 break;
657 case SANE_TYPE_BOOL:
658 case SANE_TYPE_STRING:
659 case SANE_TYPE_GROUP:
660 break;
663 else if( pButton == mpAdvancedBox )
665 ReloadSaneOptionsHdl( NULL );
668 if( pButton == mpOKButton || pButton == mpScanButton )
670 double fRes = (double)mpReslBox->GetValue();
671 SetAdjustedNumericalValue( "resolution", fRes );
672 UpdateScanArea(true);
673 SaveState();
674 EndDialog( mrSane.IsOpen() ? 1 : 0 );
675 doScan = (pButton == mpScanButton);
677 else if( pButton == mpCancelButton )
679 mrSane.Close();
680 EndDialog( 0 );
682 return 0;
685 IMPL_LINK( SaneDlg, SelectHdl, ListBox*, pListBox )
687 if( pListBox == mpDeviceBox && Sane::IsSane() && Sane::CountDevices() )
689 int nNewNumber = mpDeviceBox->GetSelectEntryPos();
690 int nOldNumber = mrSane.GetDeviceNumber();
691 if (nNewNumber != nOldNumber)
693 mrSane.Close();
694 mrSane.Open(nNewNumber);
695 mpPreview->ResetForNewScanner();
696 InitFields();
699 if( mrSane.IsOpen() )
701 if( pListBox == mpQuantumRangeBox )
703 OString aValue(OUStringToOString(mpQuantumRangeBox->GetSelectEntry(),
704 osl_getThreadTextEncoding()));
705 double fValue = atof(aValue.getStr());
706 mrSane.SetOptionValue( mnCurrentOption, fValue, mnCurrentElement );
708 else if( pListBox == mpStringRangeBox )
710 mrSane.SetOptionValue( mnCurrentOption, mpStringRangeBox->GetSelectEntry() );
713 return 0;
716 IMPL_LINK( SaneDlg, OptionsBoxSelectHdl, SvTreeListBox*, pBox )
718 if( pBox == mpOptionBox && Sane::IsSane() )
720 OUString aOption =
721 mpOptionBox->GetEntryText( mpOptionBox->FirstSelected() );
722 int nOption = mrSane.GetOptionByName(OUStringToOString(aOption,
723 osl_getThreadTextEncoding()).getStr());
724 if( nOption != -1 && nOption != mnCurrentOption )
726 DisableOption();
727 mnCurrentOption = nOption;
728 mpOptionTitle->SetText( mrSane.GetOptionTitle( mnCurrentOption ) );
729 SANE_Value_Type nType = mrSane.GetOptionType( mnCurrentOption );
730 SANE_Constraint_Type nConstraint;
731 switch( nType )
733 case SANE_TYPE_BOOL: EstablishBoolOption();break;
734 case SANE_TYPE_STRING:
735 nConstraint = mrSane.GetOptionConstraintType( mnCurrentOption );
736 if( nConstraint == SANE_CONSTRAINT_STRING_LIST )
737 EstablishStringRange();
738 else
739 EstablishStringOption();
740 break;
741 case SANE_TYPE_FIXED:
742 case SANE_TYPE_INT:
744 nConstraint = mrSane.GetOptionConstraintType( mnCurrentOption );
745 int nElements = mrSane.GetOptionElements( mnCurrentOption );
746 mnCurrentElement = 0;
747 if( nConstraint == SANE_CONSTRAINT_RANGE ||
748 nConstraint == SANE_CONSTRAINT_WORD_LIST )
749 EstablishQuantumRange();
750 else
752 mfMin = mfMax = 0.0;
753 EstablishNumericOption();
755 if( nElements > 1 )
757 if( nElements <= 10 )
759 mpVectorBox->SetValue( 1 );
760 mpVectorBox->SetMin( 1 );
761 mpVectorBox->SetMax(
762 mrSane.GetOptionElements( mnCurrentOption ) );
763 mpVectorBox->Show( true );
764 mpVectorTxt->Show( true );
766 else
768 DisableOption();
769 // bring up dialog only on button click
770 EstablishButtonOption();
774 break;
775 case SANE_TYPE_BUTTON:
776 EstablishButtonOption();
777 break;
778 default: break;
782 return 0;
785 IMPL_LINK( SaneDlg, ModifyHdl, Edit*, pEdit )
787 if( mrSane.IsOpen() )
789 if( pEdit == mpStringEdit )
791 mrSane.SetOptionValue( mnCurrentOption, mpStringEdit->GetText() );
793 else if( pEdit == mpReslBox )
795 double fRes = (double)mpReslBox->GetValue();
796 int nOption = mrSane.GetOptionByName( "resolution" );
797 if( nOption != -1 )
799 double* pDouble = NULL;
800 int nValues = mrSane.GetRange( nOption, pDouble );
801 if( nValues > 0 )
803 int i;
804 for( i = 0; i < nValues; i++ )
806 if( fRes == pDouble[i] )
807 break;
809 if( i >= nValues )
810 fRes = pDouble[0];
812 else if( nValues == 0 )
814 if( fRes < pDouble[ 0 ] )
815 fRes = pDouble[ 0 ];
816 if( fRes > pDouble[ 1 ] )
817 fRes = pDouble[ 1 ];
819 delete[] pDouble;
820 mpReslBox->SetValue( (sal_uLong)fRes );
823 else if( pEdit == mpNumericEdit )
825 double fValue;
826 OString aContents(OUStringToOString(mpNumericEdit->GetText(),
827 osl_getThreadTextEncoding()));
828 fValue = atof(aContents.getStr());
829 if( mfMin != mfMax && ( fValue < mfMin || fValue > mfMax ) )
831 char pBuf[256];
832 if( fValue < mfMin )
833 fValue = mfMin;
834 else if( fValue > mfMax )
835 fValue = mfMax;
836 sprintf( pBuf, "%g", fValue );
837 mpNumericEdit->SetText( OUString( pBuf, strlen(pBuf), osl_getThreadTextEncoding() ) );
839 mrSane.SetOptionValue( mnCurrentOption, fValue, mnCurrentElement );
841 else if( pEdit == mpVectorBox )
843 mnCurrentElement = mpVectorBox->GetValue()-1;
844 double fValue;
845 if( mrSane.GetOptionValue( mnCurrentOption, fValue, mnCurrentElement ))
847 char pBuf[256];
848 sprintf( pBuf, "%g", fValue );
849 OUString aValue( pBuf, strlen(pBuf), osl_getThreadTextEncoding() );
850 mpNumericEdit->SetText( aValue );
851 mpQuantumRangeBox->SelectEntry( aValue );
854 else if( pEdit == mpTopField )
856 mpPreview->ChangePreviewLogicTopLeftY(mpTopField->GetValue());
857 mpPreview->Invalidate();
859 else if( pEdit == mpLeftField )
861 mpPreview->ChangePreviewLogicTopLeftX(mpLeftField->GetValue());
862 mpPreview->Invalidate();
864 else if( pEdit == mpBottomField )
866 mpPreview->ChangePreviewLogicBottomRightY(mpBottomField->GetValue());
867 mpPreview->Invalidate();
869 else if( pEdit == mpRightField )
871 mpPreview->ChangePreviewLogicBottomRightX(mpRightField->GetValue());
872 mpPreview->Invalidate();
875 return 0;
878 IMPL_LINK( SaneDlg, ReloadSaneOptionsHdl, Sane*, /*pSane*/ )
880 mnCurrentOption = -1;
881 mnCurrentElement = 0;
882 DisableOption();
883 InitFields();
884 mpPreview->Invalidate();
885 return 0;
888 void SaneDlg::AcquirePreview()
890 if( ! mrSane.IsOpen() )
891 return;
893 UpdateScanArea( true );
894 // set small resolution for preview
895 double fResl = (double)mpReslBox->GetValue();
896 SetAdjustedNumericalValue( "resolution", 30.0 );
898 int nOption = mrSane.GetOptionByName( "preview" );
899 if( nOption == -1 )
901 OUString aString(SaneResId(STR_SLOW_PREVIEW));
902 ScopedVclPtrInstance< MessageDialog > aBox(this, aString, VCL_MESSAGE_WARNING, VCL_BUTTONS_OK_CANCEL);
903 if (aBox->Execute() == RET_CANCEL)
904 return;
906 else
907 mrSane.SetOptionValue( nOption, true );
909 BitmapTransporter aTransporter;
910 if( ! mrSane.Start( aTransporter ) )
912 ScopedVclPtrInstance< MessageDialog > aErrorBox(this, SaneResId(STR_ERROR_SCAN));
913 aErrorBox->Execute();
915 else
917 #if OSL_DEBUG_LEVEL > 1
918 aTransporter.getStream().Seek( STREAM_SEEK_TO_END );
919 fprintf( stderr, "Previewbitmapstream contains %d bytes\n", (int)aTransporter.getStream().Tell() );
920 #endif
921 aTransporter.getStream().Seek( STREAM_SEEK_TO_BEGIN );
922 mpPreview->SetBitmap(aTransporter.getStream());
925 SetAdjustedNumericalValue( "resolution", fResl );
926 mpReslBox->SetValue( (sal_uLong)fResl );
928 mpPreview->UpdatePreviewBounds();
929 mpPreview->Invalidate();
932 void ScanPreview::UpdatePreviewBounds()
934 if( mbDragEnable )
936 maPreviewRect = Rectangle( maTopLeft,
937 Size( maBottomRight.X() - maTopLeft.X(),
938 maBottomRight.Y() - maTopLeft.Y() )
941 else
943 Size aBMSize( maPreviewBitmap.GetSizePixel() );
944 if( aBMSize.Width() > aBMSize.Height() && aBMSize.Width() )
946 int nVHeight = (maBottomRight.X() - maTopLeft.X()) * aBMSize.Height() / aBMSize.Width();
947 maPreviewRect = Rectangle( Point( maTopLeft.X(), ( maTopLeft.Y() + maBottomRight.Y() )/2 - nVHeight/2 ),
948 Size( maBottomRight.X() - maTopLeft.X(),
949 nVHeight ) );
951 else if (aBMSize.Height())
953 int nVWidth = (maBottomRight.Y() - maTopLeft.Y()) * aBMSize.Width() / aBMSize.Height();
954 maPreviewRect = Rectangle( Point( ( maTopLeft.X() + maBottomRight.X() )/2 - nVWidth/2, maTopLeft.Y() ),
955 Size( nVWidth,
956 maBottomRight.Y() - maTopLeft.Y() ) );
961 void ScanPreview::Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect)
963 Window::Paint(rRenderContext, rRect);
964 rRenderContext.SetMapMode(MAP_APPFONT);
965 rRenderContext.SetFillColor(Color(COL_WHITE));
966 rRenderContext.SetLineColor(Color(COL_WHITE));
967 rRenderContext.DrawRect(Rectangle(Point(0, 0),
968 Size(PREVIEW_WIDTH, PREVIEW_HEIGHT)));
969 rRenderContext.SetMapMode(MapMode(MAP_PIXEL));
970 // check for sane values
971 rRenderContext.DrawBitmap(maPreviewRect.TopLeft(), maPreviewRect.GetSize(), maPreviewBitmap);
973 mbDragDrawn = false;
974 DrawDrag(rRenderContext);
977 void SaneDlg::DisableOption()
979 mpBoolCheckBox->Show( false );
980 mpStringEdit->Show( false );
981 mpNumericEdit->Show( false );
982 mpQuantumRangeBox->Show( false );
983 mpStringRangeBox->Show( false );
984 mpButtonOption->Show( false );
985 mpVectorBox->Show( false );
986 mpVectorTxt->Show( false );
987 mpOptionDescTxt->Show( false );
990 void SaneDlg::EstablishBoolOption()
992 bool bSuccess, bValue;
994 bSuccess = mrSane.GetOptionValue( mnCurrentOption, bValue );
995 if( bSuccess )
997 mpBoolCheckBox->SetText( mrSane.GetOptionName( mnCurrentOption ) );
998 mpBoolCheckBox->Check( bValue );
999 mpBoolCheckBox->Show( true );
1003 void SaneDlg::EstablishStringOption()
1005 bool bSuccess;
1006 OString aValue;
1008 bSuccess = mrSane.GetOptionValue( mnCurrentOption, aValue );
1009 if( bSuccess )
1011 mpOptionDescTxt->SetText( mrSane.GetOptionName( mnCurrentOption ) );
1012 mpOptionDescTxt->Show( true );
1013 mpStringEdit->SetText(OStringToOUString(aValue, osl_getThreadTextEncoding()));
1014 mpStringEdit->Show( true );
1018 void SaneDlg::EstablishStringRange()
1020 const char** ppStrings = mrSane.GetStringConstraint( mnCurrentOption );
1021 mpStringRangeBox->Clear();
1022 for( int i = 0; ppStrings[i] != 0; i++ )
1023 mpStringRangeBox->InsertEntry( OUString( ppStrings[i], strlen(ppStrings[i]), osl_getThreadTextEncoding() ) );
1024 OString aValue;
1025 mrSane.GetOptionValue( mnCurrentOption, aValue );
1026 mpStringRangeBox->SelectEntry(OStringToOUString(aValue, osl_getThreadTextEncoding()));
1027 mpStringRangeBox->Show( true );
1028 mpOptionDescTxt->SetText( mrSane.GetOptionName( mnCurrentOption ) );
1029 mpOptionDescTxt->Show( true );
1032 void SaneDlg::EstablishQuantumRange()
1034 if( mpRange )
1036 delete [] mpRange;
1037 mpRange = 0;
1039 int nValues = mrSane.GetRange( mnCurrentOption, mpRange );
1040 if( nValues == 0 )
1042 mfMin = mpRange[ 0 ];
1043 mfMax = mpRange[ 1 ];
1044 delete [] mpRange;
1045 mpRange = 0;
1046 EstablishNumericOption();
1048 else if( nValues > 0 )
1050 char pBuf[ 256 ];
1051 mpQuantumRangeBox->Clear();
1052 mfMin = mpRange[ 0 ];
1053 mfMax = mpRange[ nValues-1 ];
1054 for( int i = 0; i < nValues; i++ )
1056 sprintf( pBuf, "%g", mpRange[ i ] );
1057 mpQuantumRangeBox->InsertEntry( OUString( pBuf, strlen(pBuf), osl_getThreadTextEncoding() ) );
1059 double fValue;
1060 if( mrSane.GetOptionValue( mnCurrentOption, fValue, mnCurrentElement ) )
1062 sprintf( pBuf, "%g", fValue );
1063 mpQuantumRangeBox->SelectEntry( OUString( pBuf, strlen(pBuf), osl_getThreadTextEncoding() ) );
1065 mpQuantumRangeBox->Show( true );
1066 OUString aText( mrSane.GetOptionName( mnCurrentOption ) );
1067 aText += " ";
1068 aText += mrSane.GetOptionUnitName( mnCurrentOption );
1069 mpOptionDescTxt->SetText( aText );
1070 mpOptionDescTxt->Show( true );
1074 void SaneDlg::EstablishNumericOption()
1076 bool bSuccess;
1077 double fValue;
1079 bSuccess = mrSane.GetOptionValue( mnCurrentOption, fValue );
1080 if( ! bSuccess )
1081 return;
1083 char pBuf[256];
1084 OUString aText( mrSane.GetOptionName( mnCurrentOption ) );
1085 aText += " ";
1086 aText += mrSane.GetOptionUnitName( mnCurrentOption );
1087 if( mfMin != mfMax )
1089 sprintf( pBuf, " < %g ; %g >", mfMin, mfMax );
1090 aText += OUString( pBuf, strlen(pBuf), osl_getThreadTextEncoding() );
1092 mpOptionDescTxt->SetText( aText );
1093 mpOptionDescTxt->Show( true );
1094 sprintf( pBuf, "%g", fValue );
1095 mpNumericEdit->SetText( OUString( pBuf, strlen(pBuf), osl_getThreadTextEncoding() ) );
1096 mpNumericEdit->Show( true );
1099 void SaneDlg::EstablishButtonOption()
1101 mpOptionDescTxt->SetText( mrSane.GetOptionName( mnCurrentOption ) );
1102 mpOptionDescTxt->Show( true );
1103 mpButtonOption->Show( true );
1106 void ScanPreview::MouseMove(const MouseEvent& rMEvt)
1108 if( mbIsDragging )
1110 Point aMousePos = rMEvt.GetPosPixel();
1111 // move into valid area
1112 Point aLogicPos = GetLogicPos( aMousePos );
1113 aMousePos = GetPixelPos( aLogicPos );
1114 switch( meDragDirection )
1116 case TopLeft: maTopLeft = aMousePos; break;
1117 case Top: maTopLeft.Y() = aMousePos.Y(); break;
1118 case TopRight:
1119 maTopLeft.Y() = aMousePos.Y();
1120 maBottomRight.X() = aMousePos.X();
1121 break;
1122 case Right: maBottomRight.X() = aMousePos.X(); break;
1123 case BottomRight: maBottomRight = aMousePos; break;
1124 case Bottom: maBottomRight.Y() = aMousePos.Y(); break;
1125 case BottomLeft:
1126 maTopLeft.X() = aMousePos.X();
1127 maBottomRight.Y() = aMousePos.Y();
1128 break;
1129 case Left: maTopLeft.X() = aMousePos.X(); break;
1130 default: break;
1132 int nSwap;
1133 if( maTopLeft.X() > maBottomRight.X() )
1135 nSwap = maTopLeft.X();
1136 maTopLeft.X() = maBottomRight.X();
1137 maBottomRight.X() = nSwap;
1139 if( maTopLeft.Y() > maBottomRight.Y() )
1141 nSwap = maTopLeft.Y();
1142 maTopLeft.Y() = maBottomRight.Y();
1143 maBottomRight.Y() = nSwap;
1145 Invalidate();
1146 mpParentDialog->UpdateScanArea(false);
1148 Window::MouseMove( rMEvt );
1151 void ScanPreview::MouseButtonDown( const MouseEvent& rMEvt )
1153 Point aMousePixel = rMEvt.GetPosPixel();
1155 if( ! mbIsDragging && mbDragEnable )
1157 int nMiddleX = ( maBottomRight.X() - maTopLeft.X() ) / 2 - RECT_SIZE_PIX/2 + maTopLeft.X();
1158 int nMiddleY = ( maBottomRight.Y() - maTopLeft.Y() ) / 2 - RECT_SIZE_PIX/2 + maTopLeft.Y();
1159 if( aMousePixel.Y() >= maTopLeft.Y() &&
1160 aMousePixel.Y() < maTopLeft.Y() + RECT_SIZE_PIX )
1162 if( aMousePixel.X() >= maTopLeft.X() &&
1163 aMousePixel.X() < maTopLeft.X() + RECT_SIZE_PIX )
1165 meDragDirection = TopLeft;
1166 aMousePixel = maTopLeft;
1167 mbIsDragging = true;
1169 else if( aMousePixel.X() >= nMiddleX &&
1170 aMousePixel.X() < nMiddleX + RECT_SIZE_PIX )
1172 meDragDirection = Top;
1173 aMousePixel.Y() = maTopLeft.Y();
1174 mbIsDragging = true;
1176 else if( aMousePixel.X() > maBottomRight.X() - RECT_SIZE_PIX &&
1177 aMousePixel.X() <= maBottomRight.X() )
1179 meDragDirection = TopRight;
1180 aMousePixel = Point( maBottomRight.X(), maTopLeft.Y() );
1181 mbIsDragging = true;
1184 else if( aMousePixel.Y() >= nMiddleY &&
1185 aMousePixel.Y() < nMiddleY + RECT_SIZE_PIX )
1187 if( aMousePixel.X() >= maTopLeft.X() &&
1188 aMousePixel.X() < maTopLeft.X() + RECT_SIZE_PIX )
1190 meDragDirection = Left;
1191 aMousePixel.X() = maTopLeft.X();
1192 mbIsDragging = true;
1194 else if( aMousePixel.X() > maBottomRight.X() - RECT_SIZE_PIX &&
1195 aMousePixel.X() <= maBottomRight.X() )
1197 meDragDirection = Right;
1198 aMousePixel.X() = maBottomRight.X();
1199 mbIsDragging = true;
1202 else if( aMousePixel.Y() <= maBottomRight.Y() &&
1203 aMousePixel.Y() > maBottomRight.Y() - RECT_SIZE_PIX )
1205 if( aMousePixel.X() >= maTopLeft.X() &&
1206 aMousePixel.X() < maTopLeft.X() + RECT_SIZE_PIX )
1208 meDragDirection = BottomLeft;
1209 aMousePixel = Point( maTopLeft.X(), maBottomRight.Y() );
1210 mbIsDragging = true;
1212 else if( aMousePixel.X() >= nMiddleX &&
1213 aMousePixel.X() < nMiddleX + RECT_SIZE_PIX )
1215 meDragDirection = Bottom;
1216 aMousePixel.Y() = maBottomRight.Y();
1217 mbIsDragging = true;
1219 else if( aMousePixel.X() > maBottomRight.X() - RECT_SIZE_PIX &&
1220 aMousePixel.X() <= maBottomRight.X() )
1222 meDragDirection = BottomRight;
1223 aMousePixel = maBottomRight;
1224 mbIsDragging = true;
1228 if( mbIsDragging )
1230 SetPointerPosPixel( aMousePixel );
1231 Invalidate();
1233 Window::MouseButtonDown( rMEvt );
1236 void ScanPreview::MouseButtonUp( const MouseEvent& rMEvt )
1238 if( mbIsDragging )
1240 mpParentDialog->UpdateScanArea(true);
1242 mbIsDragging = false;
1244 Window::MouseButtonUp( rMEvt );
1247 void ScanPreview::DrawDrag(vcl::RenderContext& rRenderContext)
1249 static Point aLastUL, aLastBR;
1251 if (!mbDragEnable)
1252 return;
1254 RasterOp eROP = rRenderContext.GetRasterOp();
1255 rRenderContext.SetRasterOp(ROP_INVERT);
1256 rRenderContext.SetMapMode(MapMode(MAP_PIXEL));
1258 if (mbDragDrawn)
1259 DrawRectangles(rRenderContext, aLastUL, aLastBR);
1261 aLastUL = maTopLeft;
1262 aLastBR = maBottomRight;
1263 DrawRectangles(rRenderContext, maTopLeft, maBottomRight);
1265 mbDragDrawn = true;
1266 rRenderContext.SetRasterOp(eROP);
1267 rRenderContext.SetMapMode(MAP_APPFONT);
1270 Point ScanPreview::GetPixelPos( const Point& rIn) const
1272 Point aConvert(
1273 ( ( rIn.X() * PREVIEW_WIDTH ) /
1274 ( maMaxBottomRight.X() - maMinTopLeft.X() ) )
1276 ( ( rIn.Y() * PREVIEW_HEIGHT )
1277 / ( maMaxBottomRight.Y() - maMinTopLeft.Y() ) )
1280 return LogicToPixel(aConvert, MAP_APPFONT);
1283 Point ScanPreview::GetLogicPos(const Point& rIn) const
1285 Point aConvert = PixelToLogic(rIn, MAP_APPFONT);
1286 if( aConvert.X() < 0 )
1287 aConvert.X() = 0;
1288 if( aConvert.X() >= PREVIEW_WIDTH )
1289 aConvert.X() = PREVIEW_WIDTH-1;
1290 if( aConvert.Y() < 0 )
1291 aConvert.Y() = 0;
1292 if( aConvert.Y() >= PREVIEW_HEIGHT )
1293 aConvert.Y() = PREVIEW_HEIGHT-1;
1295 aConvert.X() *= ( maMaxBottomRight.X() - maMinTopLeft.X() );
1296 aConvert.X() /= PREVIEW_WIDTH;
1297 aConvert.Y() *= ( maMaxBottomRight.Y() - maMinTopLeft.Y() );
1298 aConvert.Y() /= PREVIEW_HEIGHT;
1299 return aConvert;
1302 void SaneDlg::UpdateScanArea(bool bSend)
1304 if (!mpPreview->IsDragEnabled())
1305 return;
1307 Point aUL, aBR;
1308 mpPreview->GetPreviewLogicRect(aUL, aBR);
1310 mpLeftField->SetValue( aUL.X() );
1311 mpTopField->SetValue( aUL.Y() );
1312 mpRightField->SetValue( aBR.X() );
1313 mpBottomField->SetValue( aBR.Y() );
1315 if (!bSend)
1316 return;
1318 if( mrSane.IsOpen() )
1320 SetAdjustedNumericalValue( "tl-x", (double)aUL.X() );
1321 SetAdjustedNumericalValue( "tl-y", (double)aUL.Y() );
1322 SetAdjustedNumericalValue( "br-x", (double)aBR.X() );
1323 SetAdjustedNumericalValue( "br-y", (double)aBR.Y() );
1327 bool SaneDlg::LoadState()
1329 int i;
1331 if( ! Sane::IsSane() )
1332 return false;
1334 const char* pEnv = getenv("HOME");
1335 OUString aFileName = pEnv ? OUString(pEnv, strlen(pEnv), osl_getThreadTextEncoding() ) : OUString();
1336 aFileName += "/.so_sane_state";
1337 Config aConfig( aFileName );
1338 if( ! aConfig.HasGroup( "SANE" ) )
1339 return false;
1341 aConfig.SetGroup( "SANE" );
1342 OString aString = aConfig.ReadKey( "SO_LastSaneDevice" );
1343 for( i = 0; i < Sane::CountDevices() && !aString.equals(OUStringToOString(Sane::GetName(i), osl_getThreadTextEncoding())); i++ ) ;
1344 if( i == Sane::CountDevices() )
1345 return false;
1347 mrSane.Close();
1348 mrSane.Open( aString.getStr() );
1350 DisableOption();
1351 InitFields();
1353 if( mrSane.IsOpen() )
1355 int iMax = aConfig.GetKeyCount();
1356 for (i = 0; i < iMax; ++i)
1358 aString = aConfig.GetKeyName( i );
1359 OString aValue = aConfig.ReadKey( i );
1360 int nOption = mrSane.GetOptionByName( aString.getStr() );
1361 if( nOption == -1 )
1362 continue;
1364 if (aValue.startsWith("BOOL="))
1366 aValue = aValue.copy(RTL_CONSTASCII_LENGTH("BOOL="));
1367 bool aBOOL = aValue.toInt32() != 0;
1368 mrSane.SetOptionValue( nOption, aBOOL );
1370 else if (aValue.startsWith("STRING="))
1372 aValue = aValue.copy(RTL_CONSTASCII_LENGTH("STRING="));
1373 mrSane.SetOptionValue(nOption,OStringToOUString(aValue, osl_getThreadTextEncoding()) );
1375 else if (aValue.startsWith("NUMERIC="))
1377 aValue = aValue.copy(RTL_CONSTASCII_LENGTH("NUMERIC="));
1379 sal_Int32 nIndex = 0;
1380 int n = 0;
1383 OString aSub = aValue.getToken(0, ':', nIndex);
1384 double fValue=0.0;
1385 sscanf(aSub.getStr(), "%lg", &fValue);
1386 SetAdjustedNumericalValue(aString.getStr(), fValue, n++);
1388 while ( nIndex >= 0 );
1393 DisableOption();
1394 InitFields();
1396 return true;
1399 void SaneDlg::SaveState()
1401 if( ! Sane::IsSane() )
1402 return;
1404 const char* pEnv = getenv( "HOME" );
1405 OUString aFileName;
1407 if( pEnv )
1408 aFileName = OUString::createFromAscii(pEnv) + "/.so_sane_state";
1409 else
1410 aFileName = OStringToOUString("", osl_getThreadTextEncoding()) + "/.so_sane_state";
1412 Config aConfig( aFileName );
1413 aConfig.DeleteGroup( "SANE" );
1414 aConfig.SetGroup( "SANE" );
1415 aConfig.WriteKey( "SO_LastSANEDevice",
1416 OUStringToOString(mpDeviceBox->GetSelectEntry(), RTL_TEXTENCODING_UTF8) );
1418 static char const* pSaveOptions[] = {
1419 "resolution",
1420 "tl-x",
1421 "tl-y",
1422 "br-x",
1423 "br-y"
1425 for( size_t i = 0; i < SAL_N_ELEMENTS(pSaveOptions); ++i )
1427 OString aOption = pSaveOptions[i];
1428 int nOption = mrSane.GetOptionByName( pSaveOptions[i] );
1429 if( nOption > -1 )
1431 SANE_Value_Type nType = mrSane.GetOptionType( nOption );
1432 switch( nType )
1434 case SANE_TYPE_BOOL:
1436 bool bValue;
1437 if( mrSane.GetOptionValue( nOption, bValue ) )
1439 OStringBuffer aString("BOOL=");
1440 aString.append(static_cast<sal_Int32>(bValue));
1441 aConfig.WriteKey(aOption, aString.makeStringAndClear());
1444 break;
1445 case SANE_TYPE_STRING:
1447 OString aValue;
1448 if( mrSane.GetOptionValue( nOption, aValue ) )
1450 OStringBuffer aString("STRING=");
1451 aString.append(aValue);
1452 aConfig.WriteKey( aOption, aString.makeStringAndClear() );
1455 break;
1456 case SANE_TYPE_FIXED:
1457 case SANE_TYPE_INT:
1459 OStringBuffer aString("NUMERIC=");
1460 double fValue;
1461 char buf[256];
1462 int n;
1464 for( n = 0; n < mrSane.GetOptionElements( nOption ); n++ )
1466 if( ! mrSane.GetOptionValue( nOption, fValue, n ) )
1467 break;
1468 if( n > 0 )
1469 aString.append(':');
1470 sprintf( buf, "%lg", fValue );
1471 aString.append(buf);
1473 if( n >= mrSane.GetOptionElements( nOption ) )
1474 aConfig.WriteKey( aOption, aString.makeStringAndClear() );
1476 break;
1477 default:
1478 break;
1484 bool SaneDlg::SetAdjustedNumericalValue(
1485 const char* pOption,
1486 double fValue,
1487 int nElement )
1489 int nOption;
1490 if( ! Sane::IsSane() || ! mrSane.IsOpen() || ( nOption = mrSane.GetOptionByName( pOption ) ) == -1 )
1491 return false;
1493 if( nElement < 0 || nElement >= mrSane.GetOptionElements( nOption ) )
1494 return false;
1496 double* pValues = NULL;
1497 int nValues;
1498 if( ( nValues = mrSane.GetRange( nOption, pValues ) ) < 0 )
1500 delete [] pValues;
1501 return false;
1504 #if OSL_DEBUG_LEVEL > 1
1505 fprintf( stderr, "SaneDlg::SetAdjustedNumericalValue( \"%s\", %lg ) ",
1506 pOption, fValue );
1507 #endif
1509 if( nValues )
1511 int nNearest = 0;
1512 double fNearest = 1e6;
1513 for( int i = 0; i < nValues; i++ )
1515 if( fabs( fValue - pValues[ i ] ) < fNearest )
1517 fNearest = fabs( fValue - pValues[ i ] );
1518 nNearest = i;
1521 fValue = pValues[ nNearest ];
1523 else
1525 if( fValue < pValues[0] )
1526 fValue = pValues[0];
1527 if( fValue > pValues[1] )
1528 fValue = pValues[1];
1530 delete [] pValues;
1531 mrSane.SetOptionValue( nOption, fValue, nElement );
1532 #if OSL_DEBUG_LEVEL > 1
1533 fprintf( stderr, "yields %lg\n", fValue );
1534 #endif
1537 return true;
1541 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */