4 * Copyright 2006 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #define NONAMELESSUNION
34 #include "wine/debug.h"
36 #include "wine/unicode.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(twain
);
43 #define ID_EDIT_BASE 0x1000
44 #define ID_STATIC_BASE 0x2000
46 static INT_PTR CALLBACK
DialogProc (HWND
, UINT
, WPARAM
, LPARAM
);
47 static INT CALLBACK
PropSheetProc(HWND
, UINT
,LPARAM
);
49 static int create_leading_static(HDC hdc
, LPCSTR text
,
50 LPDLGITEMTEMPLATEW
* template_out
, int y
, int id
)
52 LPDLGITEMTEMPLATEW tpl
= NULL
;
63 base
= GetDialogBaseUnits();
65 len
= MultiByteToWideChar(CP_ACP
,0,text
,-1,NULL
,0);
67 len
+= sizeof(DLGITEMTEMPLATE
);
68 len
+= 3*sizeof(WORD
);
70 tpl
= HeapAlloc(GetProcessHeap(),0,len
);
71 tpl
->style
=WS_VISIBLE
;
72 tpl
->dwExtendedStyle
= 0;
77 GetTextExtentPoint32A(hdc
,text
,lstrlenA(text
),&size
);
79 tpl
->cx
= MulDiv(size
.cx
,4,LOWORD(base
));
80 tpl
->cy
= MulDiv(size
.cy
,8,HIWORD(base
)) * 2;
81 ptr
= (LPBYTE
)tpl
+ sizeof(DLGITEMTEMPLATE
);
82 *(LPWORD
)ptr
= 0xffff;
84 *(LPWORD
)ptr
= 0x0082;
86 ptr
+= MultiByteToWideChar(CP_ACP
,0,text
,-1,(LPWSTR
)ptr
,len
) * sizeof(WCHAR
);
87 *(LPWORD
)ptr
= 0x0000;
93 static int create_trailing_edit(HDC hdc
, LPDLGITEMTEMPLATEW
* template_out
, int id
,
94 int y
, LPCSTR text
,BOOL is_int
)
96 LPDLGITEMTEMPLATEW tpl
= NULL
;
101 static const char int_base
[] = "0000 xxx";
102 static const char float_base
[] = "0000.0000 xxx";
104 base
= GetDialogBaseUnits();
106 len
= MultiByteToWideChar(CP_ACP
,0,text
,-1,NULL
,0);
107 len
*= sizeof(WCHAR
);
108 len
+= sizeof(DLGITEMTEMPLATE
);
109 len
+= 3*sizeof(WORD
);
111 tpl
= HeapAlloc(GetProcessHeap(),0,len
);
112 tpl
->style
=WS_VISIBLE
|ES_READONLY
|WS_BORDER
;
113 tpl
->dwExtendedStyle
= 0;
119 GetTextExtentPoint32A(hdc
,int_base
,lstrlenA(int_base
),&size
);
121 GetTextExtentPoint32A(hdc
,float_base
,lstrlenA(float_base
),&size
);
123 tpl
->cx
= MulDiv(size
.cx
*2,4,LOWORD(base
));
124 tpl
->cy
= MulDiv(size
.cy
,8,HIWORD(base
)) * 2;
126 ptr
= (LPBYTE
)tpl
+ sizeof(DLGITEMTEMPLATE
);
127 *(LPWORD
)ptr
= 0xffff;
129 *(LPWORD
)ptr
= 0x0081;
131 ptr
+= MultiByteToWideChar(CP_ACP
,0,text
,-1,(LPWSTR
)ptr
,len
) * sizeof(WCHAR
);
132 *(LPWORD
)ptr
= 0x0000;
139 static int create_item(HDC hdc
, const SANE_Option_Descriptor
*opt
,
140 INT id
, LPDLGITEMTEMPLATEW
*template_out
, int y
, int *cx
, int* count
)
142 LPDLGITEMTEMPLATEW tpl
= NULL
,rc
= NULL
;
144 DWORD styles
= WS_VISIBLE
;
146 LPDLGITEMTEMPLATEW lead_static
= NULL
;
147 LPDLGITEMTEMPLATEW trail_edit
= NULL
;
148 DWORD leading_len
= 0;
160 GetTextExtentPoint32A(hdc
,"X",1,&size
);
161 base
= GetDialogBaseUnits();
162 base_x
= MulDiv(size
.cx
,4,LOWORD(base
));
164 if (opt
->type
== SANE_TYPE_BOOL
)
166 class = 0x0080; /* Button */
167 styles
|= BS_AUTOCHECKBOX
;
168 local_len
+= MultiByteToWideChar(CP_ACP
,0,opt
->title
,-1,NULL
,0);
169 local_len
*= sizeof(WCHAR
);
172 else if (opt
->type
== SANE_TYPE_INT
)
176 psane_control_option(activeDS
.deviceHandle
, id
-ID_BASE
,
177 SANE_ACTION_GET_VALUE
, &i
,NULL
);
179 sprintf(buffer
,"%i",i
);
181 if (opt
->constraint_type
== SANE_CONSTRAINT_NONE
)
183 class = 0x0081; /* Edit*/
186 local_len
+= MultiByteToWideChar(CP_ACP
,0,title
,-1,NULL
,0);
187 local_len
*= sizeof(WCHAR
);
189 else if (opt
->constraint_type
== SANE_CONSTRAINT_RANGE
)
191 class = 0x0084; /* scroll */
192 ctl_cx
= 10 * base_x
;
193 trail_len
+= create_trailing_edit(hdc
, &trail_edit
, id
+
194 ID_EDIT_BASE
, y
,buffer
,TRUE
);
198 class= 0x0085; /* Combo */
199 ctl_cx
= 10 * base_x
;
200 styles
|= CBS_DROPDOWNLIST
;
202 leading_len
+= create_leading_static(hdc
, opt
->title
, &lead_static
, y
,
205 else if (opt
->type
== SANE_TYPE_FIXED
)
210 i
= HeapAlloc(GetProcessHeap(),0,opt
->size
*sizeof(SANE_Word
));
212 psane_control_option(activeDS
.deviceHandle
, id
-ID_BASE
,
213 SANE_ACTION_GET_VALUE
, i
, NULL
);
216 sprintf(buffer
,"%f",dd
);
217 HeapFree(GetProcessHeap(),0,i
);
219 if (opt
->constraint_type
== SANE_CONSTRAINT_NONE
)
221 class = 0x0081; /* Edit */
223 local_len
+= MultiByteToWideChar(CP_ACP
,0,title
,-1,NULL
,0);
224 local_len
*= sizeof(WCHAR
);
226 else if (opt
->constraint_type
== SANE_CONSTRAINT_RANGE
)
228 class= 0x0084; /* scroll */
229 ctl_cx
= 10 * base_x
;
230 trail_len
+= create_trailing_edit(hdc
, &trail_edit
, id
+
231 ID_EDIT_BASE
, y
,buffer
,FALSE
);
235 class= 0x0085; /* Combo */
236 ctl_cx
= 10 * base_x
;
237 styles
|= CBS_DROPDOWNLIST
;
239 leading_len
+= create_leading_static(hdc
, opt
->title
, &lead_static
, y
,
242 else if (opt
->type
== SANE_TYPE_STRING
)
244 if (opt
->constraint_type
== SANE_CONSTRAINT_NONE
)
246 class = 0x0081; /* Edit*/
250 class= 0x0085; /* Combo */
251 ctl_cx
= opt
->size
* base_x
;
252 styles
|= CBS_DROPDOWNLIST
;
254 leading_len
+= create_leading_static(hdc
, opt
->title
, &lead_static
, y
,
256 psane_control_option(activeDS
.deviceHandle
, id
-ID_BASE
,
257 SANE_ACTION_GET_VALUE
, buffer
,NULL
);
260 local_len
+= MultiByteToWideChar(CP_ACP
,0,title
,-1,NULL
,0);
261 local_len
*= sizeof(WCHAR
);
263 else if (opt
->type
== SANE_TYPE_BUTTON
)
265 class = 0x0080; /* Button */
266 local_len
+= MultiByteToWideChar(CP_ACP
,0,opt
->title
,-1,NULL
,0);
267 local_len
*= sizeof(WCHAR
);
270 else if (opt
->type
== SANE_TYPE_GROUP
)
272 class = 0x0080; /* Button */
273 styles
|= BS_GROUPBOX
;
274 local_len
+= MultiByteToWideChar(CP_ACP
,0,opt
->title
,-1,NULL
,0);
275 local_len
*= sizeof(WCHAR
);
279 local_len
+= sizeof(DLGITEMTEMPLATE
);
281 local_len
+= 3*sizeof(WORD
);
283 local_len
+= 4*sizeof(WORD
);
287 padding
= leading_len
% sizeof(DWORD
);
288 rc
= HeapReAlloc(GetProcessHeap(),0,lead_static
,leading_len
+local_len
+ padding
);
289 tpl
= (LPDLGITEMTEMPLATEW
)((LPBYTE
)rc
+ leading_len
+ padding
);
292 rc
= tpl
= HeapAlloc(GetProcessHeap(),0,local_len
);
295 tpl
->dwExtendedStyle
= 0;
297 tpl
->x
= lead_static
->x
+ lead_static
->cx
+ 1;
298 else if (opt
->type
== SANE_TYPE_GROUP
)
307 GetTextExtentPoint32A(hdc
,title
,lstrlenA(title
),&size
);
314 tpl
->cy
= lead_static
->cy
;
323 ptr
= (LPBYTE
)tpl
+ sizeof(DLGITEMTEMPLATE
);
324 *(LPWORD
)ptr
= 0xffff;
326 *(LPWORD
)ptr
= class;
330 ptr
+= MultiByteToWideChar(CP_ACP
,0,title
,-1,(LPWSTR
)ptr
,local_len
) * sizeof(WCHAR
);
334 *(LPWORD
)ptr
= 0x0000;
338 *((LPWORD
)ptr
) = 0x0000;
343 trail_edit
->x
= tpl
->cx
+ tpl
->x
+ 2;
344 *cx
= trail_edit
->x
+ trail_edit
->cx
;
346 padding2
= (leading_len
+ local_len
+ padding
)% sizeof(DWORD
);
348 rc
= HeapReAlloc(GetProcessHeap(),0,rc
,leading_len
+local_len
+ padding
349 +padding2
+trail_len
);
351 memcpy(((LPBYTE
)rc
) + leading_len
+ local_len
+ padding
+ padding2
,
352 trail_edit
,trail_len
);
355 *cx
= tpl
->cx
+ tpl
->x
;
366 return leading_len
+ local_len
+ padding
+ padding2
+ trail_len
;
370 static LPDLGTEMPLATEW
create_options_page(HDC hdc
, int *from_index
,
371 SANE_Int optcount
, BOOL split_tabs
)
375 LPDLGTEMPLATEW tpl
= NULL
;
376 LPBYTE all_controls
= NULL
;
377 DWORD control_len
= 0;
379 int group_max_cx
= 0;
381 int group_offset
= -1;
382 INT control_count
= 0;
384 for (i
= *from_index
; i
< optcount
; i
++)
386 LPDLGITEMTEMPLATEW item_tpl
= NULL
;
387 const SANE_Option_Descriptor
*opt
;
392 int hold_for_group
= 0;
394 opt
= psane_get_option_descriptor(activeDS
.deviceHandle
, i
);
397 if (opt
->type
== SANE_TYPE_GROUP
&& split_tabs
)
410 if (!SANE_OPTION_IS_ACTIVE (opt
->cap
))
413 len
= create_item(hdc
, opt
, ID_BASE
+ i
, &item_tpl
, y
, &x
, &count
);
415 control_count
+= count
;
423 y
+= item_tpl
->cy
+ 1;
424 max_cx
= max(max_cx
, x
+ 2);
425 group_max_cx
= max(group_max_cx
, x
);
427 padding
= len
% sizeof(DWORD
);
432 newone
= HeapReAlloc(GetProcessHeap(),0,all_controls
,
433 control_len
+ len
+ padding
);
434 all_controls
= newone
;
435 memcpy(all_controls
+control_len
,item_tpl
,len
);
436 memset(all_controls
+control_len
+len
,0xca,padding
);
437 HeapFree(GetProcessHeap(),0,item_tpl
);
443 all_controls
= (LPBYTE
)item_tpl
;
447 all_controls
= HeapAlloc(GetProcessHeap(),0,len
+ padding
);
448 memcpy(all_controls
,item_tpl
,len
);
449 memset(all_controls
+len
,0xcb,padding
);
450 HeapFree(GetProcessHeap(),0,item_tpl
);
454 if (opt
->type
== SANE_TYPE_GROUP
)
456 if (group_offset
== -1)
458 group_offset
= control_len
;
463 LPDLGITEMTEMPLATEW group
=
464 (LPDLGITEMTEMPLATEW
)(all_controls
+group_offset
);
466 group
->cy
= hold_for_group
- group
->y
;
467 group
->cx
= group_max_cx
;
469 group
= (LPDLGITEMTEMPLATEW
)(all_controls
+control_len
);
473 group_offset
= control_len
;
477 control_len
+= len
+ padding
;
480 if ( group_offset
&& !split_tabs
)
482 LPDLGITEMTEMPLATEW group
=
483 (LPDLGITEMTEMPLATEW
)(all_controls
+group_offset
);
484 group
->cy
= y
- group
->y
;
485 group
->cx
= group_max_cx
;
492 tpl
= HeapAlloc(GetProcessHeap(),0,sizeof(DLGTEMPLATE
) + 3*sizeof(WORD
) +
495 tpl
->style
= WS_VISIBLE
| WS_OVERLAPPEDWINDOW
;
496 tpl
->dwExtendedStyle
= 0;
497 tpl
->cdit
= control_count
;
500 tpl
->cx
= max_cx
+ 10;
502 ptr
= (LPBYTE
)tpl
+ sizeof(DLGTEMPLATE
);
503 *(LPWORD
)ptr
= 0x0000;
505 *(LPWORD
)ptr
= 0x0000;
507 *(LPWORD
)ptr
= 0x0000;
509 memcpy(ptr
,all_controls
,control_len
);
511 HeapFree(GetProcessHeap(),0,all_controls
);
516 BOOL
DoScannerUI(void)
519 PROPSHEETPAGEW psp
[10];
521 PROPSHEETHEADERW psh
;
531 memset(psp
,0,sizeof(psp
));
532 rc
= psane_control_option(activeDS
.deviceHandle
, 0, SANE_ACTION_GET_VALUE
,
534 if (rc
!= SANE_STATUS_GOOD
)
536 ERR("Unable to read number of options\n");
540 while (index
< optcount
)
542 const SANE_Option_Descriptor
*opt
;
543 psp
[page_count
].u
.pResource
= create_options_page(hdc
, &index
,
545 opt
= psane_get_option_descriptor(activeDS
.deviceHandle
, index
);
547 if (opt
->type
== SANE_TYPE_GROUP
)
552 len
= MultiByteToWideChar(CP_ACP
,0,opt
->title
,-1,NULL
,0);
553 title
= HeapAlloc(GetProcessHeap(),0,len
* sizeof(WCHAR
));
554 MultiByteToWideChar(CP_ACP
,0,opt
->title
,-1,title
,len
);
556 psp
[page_count
].pszTitle
= title
;
559 if (psp
[page_count
].u
.pResource
)
561 psp
[page_count
].dwSize
= sizeof(PROPSHEETPAGEW
);
562 psp
[page_count
].dwFlags
= PSP_DLGINDIRECT
| PSP_USETITLE
;
563 psp
[page_count
].hInstance
= SANE_instance
;
564 psp
[page_count
].pfnDlgProc
= DialogProc
;
565 psp
[page_count
].lParam
= (LPARAM
)&activeDS
;
572 len
= lstrlenA(activeDS
.identity
.Manufacturer
)
573 + lstrlenA(activeDS
.identity
.ProductName
) + 2;
574 szCaption
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
575 MultiByteToWideChar(CP_ACP
,0,activeDS
.identity
.Manufacturer
,-1,
577 szCaption
[lstrlenA(activeDS
.identity
.Manufacturer
)] = ' ';
578 MultiByteToWideChar(CP_ACP
,0,activeDS
.identity
.ProductName
,-1,
579 &szCaption
[lstrlenA(activeDS
.identity
.Manufacturer
)+1],len
);
580 psh
.dwSize
= sizeof(PROPSHEETHEADERW
);
581 psh
.dwFlags
= PSH_PROPSHEETPAGE
|PSH_PROPTITLE
|PSH_USECALLBACK
;
582 psh
.hwndParent
= activeDS
.hwndOwner
;
583 psh
.hInstance
= SANE_instance
;
585 psh
.pszCaption
= szCaption
;
586 psh
.nPages
= page_count
;
587 psh
.u2
.nStartPage
= 0;
588 psh
.u3
.ppsp
= (LPCPROPSHEETPAGEW
)psp
;
589 psh
.pfnCallback
= PropSheetProc
;
591 psrc
= PropertySheetW(&psh
);
593 for(index
= 0; index
< page_count
; index
++)
595 HeapFree(GetProcessHeap(),0,(LPBYTE
)psp
[index
].u
.pResource
);
596 HeapFree(GetProcessHeap(),0,(LPBYTE
)psp
[index
].pszTitle
);
598 HeapFree(GetProcessHeap(),0,szCaption
);
606 static void UpdateRelevantEdit(HWND hwnd
, const SANE_Option_Descriptor
*opt
,
607 int index
, int position
)
613 if (opt
->type
== SANE_TYPE_INT
)
615 static const WCHAR formatW
[] = {'%','i',0};
618 if (opt
->constraint
.range
->quant
)
619 si
= position
* opt
->constraint
.range
->quant
;
623 len
= sprintfW( buffer
, formatW
, si
);
625 else if (opt
->type
== SANE_TYPE_FIXED
)
627 static const WCHAR formatW
[] = {'%','f',0};
630 s_quant
= SANE_UNFIX(opt
->constraint
.range
->quant
);
633 dd
= position
* s_quant
;
635 dd
= position
* 0.01;
637 len
= sprintfW( buffer
, formatW
, dd
);
642 LoadStringW( SANE_instance
, opt
->unit
, buffer
+ len
, sizeof(buffer
)/sizeof(WCHAR
) - len
);
644 edit_w
= GetDlgItem(hwnd
,index
+ID_BASE
+ID_EDIT_BASE
);
645 if (edit_w
) SetWindowTextW(edit_w
,buffer
);
649 static BOOL
UpdateSaneScrollOption(
650 const SANE_Option_Descriptor
*opt
, int index
, DWORD position
)
652 SANE_Status rc
= SANE_STATUS_GOOD
;
655 if (opt
->type
== SANE_TYPE_INT
)
659 if (opt
->constraint
.range
->quant
)
660 si
= position
* opt
->constraint
.range
->quant
;
664 rc
= psane_control_option (activeDS
.deviceHandle
,index
,
665 SANE_ACTION_SET_VALUE
, &si
, &result
);
668 else if (opt
->type
== SANE_TYPE_FIXED
)
673 s_quant
= SANE_UNFIX(opt
->constraint
.range
->quant
);
676 dd
= position
* s_quant
;
678 dd
= position
* 0.01;
680 sf
= HeapAlloc(GetProcessHeap(),0,opt
->size
*sizeof(SANE_Word
));
684 rc
= psane_control_option (activeDS
.deviceHandle
,index
,
685 SANE_ACTION_SET_VALUE
, sf
, &result
);
687 HeapFree(GetProcessHeap(),0,sf
);
690 if(rc
== SANE_STATUS_GOOD
)
692 if (result
& SANE_INFO_RELOAD_OPTIONS
||
693 result
& SANE_INFO_RELOAD_PARAMS
|| result
& SANE_INFO_INEXACT
)
699 static BOOL
UpdateSaneBoolOption(int index
, BOOL position
)
701 SANE_Status rc
= SANE_STATUS_GOOD
;
707 rc
= psane_control_option (activeDS
.deviceHandle
,index
,
708 SANE_ACTION_SET_VALUE
, &si
, &result
);
710 if(rc
== SANE_STATUS_GOOD
)
712 if (result
& SANE_INFO_RELOAD_OPTIONS
||
713 result
& SANE_INFO_RELOAD_PARAMS
|| result
& SANE_INFO_INEXACT
)
719 static BOOL
UpdateSaneStringOption(int index
, SANE_String value
)
721 SANE_Status rc
= SANE_STATUS_GOOD
;
724 rc
= psane_control_option (activeDS
.deviceHandle
,index
,
725 SANE_ACTION_SET_VALUE
, value
, &result
);
727 if(rc
== SANE_STATUS_GOOD
)
729 if (result
& SANE_INFO_RELOAD_OPTIONS
||
730 result
& SANE_INFO_RELOAD_PARAMS
|| result
& SANE_INFO_INEXACT
)
736 static INT_PTR
InitializeDialog(HWND hwnd
)
743 rc
= psane_control_option(activeDS
.deviceHandle
, 0, SANE_ACTION_GET_VALUE
,
745 if (rc
!= SANE_STATUS_GOOD
)
747 ERR("Unable to read number of options\n");
751 for ( i
= 1; i
< optcount
; i
++)
753 const SANE_Option_Descriptor
*opt
;
755 control
= GetDlgItem(hwnd
,i
+ID_BASE
);
760 opt
= psane_get_option_descriptor(activeDS
.deviceHandle
, i
);
762 TRACE("%i %s %i %i\n",i
,opt
->title
,opt
->type
,opt
->constraint_type
);
764 if (!SANE_OPTION_IS_ACTIVE(opt
->cap
))
765 EnableWindow(control
,FALSE
);
767 EnableWindow(control
,TRUE
);
769 SendMessageA(control
,CB_RESETCONTENT
,0,0);
770 /* initialize values */
771 if (opt
->type
== SANE_TYPE_STRING
&& opt
->constraint_type
!=
772 SANE_CONSTRAINT_NONE
)
776 while (opt
->constraint
.string_list
[j
]!=NULL
)
778 SendMessageA(control
,CB_ADDSTRING
,0,
779 (LPARAM
)opt
->constraint
.string_list
[j
]);
782 psane_control_option(activeDS
.deviceHandle
, i
, SANE_ACTION_GET_VALUE
, buffer
,NULL
);
783 SendMessageA(control
,CB_SELECTSTRING
,0,(LPARAM
)buffer
);
785 else if (opt
->type
== SANE_TYPE_BOOL
)
788 psane_control_option(activeDS
.deviceHandle
, i
,
789 SANE_ACTION_GET_VALUE
, &b
, NULL
);
791 SendMessageA(control
,BM_SETCHECK
,BST_CHECKED
,0);
794 else if (opt
->constraint_type
== SANE_CONSTRAINT_RANGE
)
796 if (opt
->type
== SANE_TYPE_INT
)
801 min
= (SANE_Int
)opt
->constraint
.range
->min
/
802 (((SANE_Int
)opt
->constraint
.range
->quant
)?
803 (SANE_Int
)opt
->constraint
.range
->quant
:1);
805 max
= (SANE_Int
)opt
->constraint
.range
->max
/
806 (((SANE_Int
)opt
->constraint
.range
->quant
)
807 ?(SANE_Int
)opt
->constraint
.range
->quant
:1);
809 SendMessageA(control
,SBM_SETRANGE
,min
,max
);
811 psane_control_option(activeDS
.deviceHandle
, i
,
812 SANE_ACTION_GET_VALUE
, &si
,NULL
);
813 if (opt
->constraint
.range
->quant
)
814 si
= si
/ opt
->constraint
.range
->quant
;
816 SendMessageW(control
,SBM_SETPOS
, si
, TRUE
);
817 UpdateRelevantEdit(hwnd
, opt
, i
, si
);
819 else if (opt
->type
== SANE_TYPE_FIXED
)
824 double s_min
,s_max
,s_quant
;
828 s_min
= SANE_UNFIX(opt
->constraint
.range
->min
);
829 s_max
= SANE_UNFIX(opt
->constraint
.range
->max
);
830 s_quant
= SANE_UNFIX(opt
->constraint
.range
->quant
);
834 min
= (s_min
/ s_quant
);
835 max
= (s_max
/ s_quant
);
843 SendMessageA(control
,SBM_SETRANGE
,min
,max
);
846 sf
= HeapAlloc(GetProcessHeap(),0,opt
->size
*sizeof(SANE_Word
));
847 psane_control_option(activeDS
.deviceHandle
, i
,
848 SANE_ACTION_GET_VALUE
, sf
,NULL
);
850 dd
= SANE_UNFIX(*sf
);
851 HeapFree(GetProcessHeap(),0,sf
);
853 /* Note that conversion of float -> SANE_Fixed is lossy;
854 * and when you truncate it into an integer, you can get
855 * unfortunate results. This calculation attempts
856 * to mitigate that harm */
858 pos
= ((dd
+ (s_quant
/2.0)) / s_quant
);
860 pos
= (dd
+ 0.005) / 0.01;
862 SendMessageW(control
, SBM_SETPOS
, pos
, TRUE
);
864 UpdateRelevantEdit(hwnd
, opt
, i
, pos
);
872 static INT_PTR
ProcessScroll(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
875 const SANE_Option_Descriptor
*opt
;
879 index
= GetDlgCtrlID((HWND
)lParam
)- ID_BASE
;
883 opt
= psane_get_option_descriptor(activeDS
.deviceHandle
, index
);
888 scroll
= LOWORD(wParam
);
893 case SB_THUMBPOSITION
:
896 si
.cbSize
= sizeof(SCROLLINFO
);
897 si
.fMask
= SIF_TRACKPOS
;
898 GetScrollInfo((HWND
)lParam
,SB_CTL
, &si
);
899 position
= si
.nTrackPos
;
905 position
= SendMessageW((HWND
)lParam
,SBM_GETPOS
,0,0);
911 position
= SendMessageW((HWND
)lParam
,SBM_GETPOS
,0,0);
915 position
= SendMessageW((HWND
)lParam
,SBM_GETPOS
,0,0);
918 SendMessageW((HWND
)lParam
,SBM_SETPOS
, position
, TRUE
);
919 position
= SendMessageW((HWND
)lParam
,SBM_GETPOS
,0,0);
921 UpdateRelevantEdit(hwnd
, opt
, index
, position
);
922 if (UpdateSaneScrollOption(opt
, index
, position
))
923 InitializeDialog(hwnd
);
929 static void ButtonClicked(HWND hwnd
, INT id
, HWND control
)
932 const SANE_Option_Descriptor
*opt
;
934 index
= id
- ID_BASE
;
938 opt
= psane_get_option_descriptor(activeDS
.deviceHandle
, index
);
943 if (opt
->type
== SANE_TYPE_BOOL
)
945 BOOL r
= SendMessageW(control
,BM_GETCHECK
,0,0)==BST_CHECKED
;
946 if (UpdateSaneBoolOption(index
, r
))
947 InitializeDialog(hwnd
);
951 static void ComboChanged(HWND hwnd
, INT id
, HWND control
)
956 const SANE_Option_Descriptor
*opt
;
959 index
= id
- ID_BASE
;
963 opt
= psane_get_option_descriptor(activeDS
.deviceHandle
, index
);
968 selection
= SendMessageW(control
,CB_GETCURSEL
,0,0);
969 len
= SendMessageW(control
,CB_GETLBTEXTLEN
,selection
,0);
972 value
= HeapAlloc(GetProcessHeap(),0,len
);
973 SendMessageA(control
,CB_GETLBTEXT
,selection
,(LPARAM
)value
);
975 if (opt
->type
== SANE_TYPE_STRING
)
977 if (UpdateSaneStringOption(index
, value
))
978 InitializeDialog(hwnd
);
983 static INT_PTR CALLBACK
DialogProc(HWND hwndDlg
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
988 return InitializeDialog(hwndDlg
);
990 return ProcessScroll(hwndDlg
, wParam
, lParam
);
993 LPPSHNOTIFY psn
= (LPPSHNOTIFY
)lParam
;
994 switch (((NMHDR
*)lParam
)->code
)
999 activeDS
.currentState
= 6;
1000 if (activeDS
.windowMessage
)
1001 PostMessageA(activeDS
.hwndOwner
, activeDS
.windowMessage
, MSG_XFERREADY
, 0);
1004 case PSN_QUERYCANCEL
:
1005 if (activeDS
.windowMessage
)
1006 PostMessageA(activeDS
.hwndOwner
, activeDS
.windowMessage
, MSG_CLOSEDSREQ
, 0);
1009 InitializeDialog(hwndDlg
);
1015 switch (HIWORD(wParam
))
1018 ButtonClicked(hwndDlg
,LOWORD(wParam
), (HWND
)lParam
);
1021 ComboChanged(hwndDlg
,LOWORD(wParam
), (HWND
)lParam
);
1028 static int CALLBACK
PropSheetProc(HWND hwnd
, UINT msg
, LPARAM lParam
)
1030 if (msg
== PSCB_INITIALIZED
)
1032 /* rename OK button to Scan */
1033 HWND scan
= GetDlgItem(hwnd
,IDOK
);
1034 SetWindowTextA(scan
,"Scan");
1040 static INT_PTR CALLBACK
ScanningProc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1045 HWND
ScanningDialogBox(HWND dialog
, LONG progress
)
1048 dialog
= CreateDialogW(SANE_instance
,
1049 (LPWSTR
)MAKEINTRESOURCE(IDD_DIALOG1
), NULL
, ScanningProc
);
1053 EndDialog(dialog
,0);
1057 RedrawWindow(dialog
,NULL
,NULL
,
1058 RDW_INTERNALPAINT
|RDW_UPDATENOW
|RDW_ALLCHILDREN
);
1063 #else /* SONAME_LIBSANE */
1065 BOOL
DoScannerUI(void)
1070 #endif /* SONAME_LIBSANE */