setupapi: Add stubs for CM_Locate_DevNodeA/W.
[wine/wine64.git] / dlls / sane.ds / ui.c
blob236a91da1f7217cb6ee6931511885404a4bd9f41
1 /*
2 * TWAIN32 Options UI
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
21 #include "config.h"
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "winnls.h"
33 #include "wingdi.h"
34 #include "prsht.h"
35 #include "twain.h"
36 #include "sane_i.h"
37 #include "wine/debug.h"
38 #include "resource.h"
39 #include "wine/unicode.h"
41 #ifdef SONAME_LIBSANE
43 WINE_DEFAULT_DEBUG_CHANNEL(twain);
45 #define ID_BASE 0x100
46 #define ID_EDIT_BASE 0x1000
47 #define ID_STATIC_BASE 0x2000
49 static INT_PTR CALLBACK DialogProc (HWND , UINT , WPARAM , LPARAM );
50 static INT CALLBACK PropSheetProc(HWND, UINT,LPARAM);
52 static int create_leading_static(HDC hdc, LPCSTR text,
53 LPDLGITEMTEMPLATEW* template_out, int y, int id)
55 LPDLGITEMTEMPLATEW tpl = NULL;
56 INT len;
57 SIZE size;
58 LPBYTE ptr;
59 LONG base;
61 *template_out = NULL;
63 if (!text)
64 return 0;
66 base = GetDialogBaseUnits();
68 len = MultiByteToWideChar(CP_ACP,0,text,-1,NULL,0);
69 len *= sizeof(WCHAR);
70 len += sizeof(DLGITEMTEMPLATE);
71 len += 3*sizeof(WORD);
73 tpl = HeapAlloc(GetProcessHeap(),0,len);
74 tpl->style=WS_VISIBLE;
75 tpl->dwExtendedStyle = 0;
76 tpl->x = 4;
77 tpl->y = y;
78 tpl->id = ID_BASE;
80 GetTextExtentPoint32A(hdc,text,lstrlenA(text),&size);
82 tpl->cx = MulDiv(size.cx,4,LOWORD(base));
83 tpl->cy = MulDiv(size.cy,8,HIWORD(base)) * 2;
84 ptr = (LPBYTE)tpl + sizeof(DLGITEMTEMPLATE);
85 *(LPWORD)ptr = 0xffff;
86 ptr += sizeof(WORD);
87 *(LPWORD)ptr = 0x0082;
88 ptr += sizeof(WORD);
89 ptr += MultiByteToWideChar(CP_ACP,0,text,-1,(LPWSTR)ptr,len) * sizeof(WCHAR);
90 *(LPWORD)ptr = 0x0000;
92 *template_out = tpl;
93 return len;
96 static int create_trailing_edit(HDC hdc, LPDLGITEMTEMPLATEW* template_out, int id,
97 int y, LPCSTR text,BOOL is_int)
99 LPDLGITEMTEMPLATEW tpl = NULL;
100 INT len;
101 LPBYTE ptr;
102 SIZE size;
103 LONG base;
104 static const char int_base[] = "0000 xxx";
105 static const char float_base[] = "0000.0000 xxx";
107 base = GetDialogBaseUnits();
109 len = MultiByteToWideChar(CP_ACP,0,text,-1,NULL,0);
110 len *= sizeof(WCHAR);
111 len += sizeof(DLGITEMTEMPLATE);
112 len += 3*sizeof(WORD);
114 tpl = HeapAlloc(GetProcessHeap(),0,len);
115 tpl->style=WS_VISIBLE|ES_READONLY|WS_BORDER;
116 tpl->dwExtendedStyle = 0;
117 tpl->x = 1;
118 tpl->y = y;
119 tpl->id = id;
121 if (is_int)
122 GetTextExtentPoint32A(hdc,int_base,lstrlenA(int_base),&size);
123 else
124 GetTextExtentPoint32A(hdc,float_base,lstrlenA(float_base),&size);
126 tpl->cx = MulDiv(size.cx*2,4,LOWORD(base));
127 tpl->cy = MulDiv(size.cy,8,HIWORD(base)) * 2;
129 ptr = (LPBYTE)tpl + sizeof(DLGITEMTEMPLATE);
130 *(LPWORD)ptr = 0xffff;
131 ptr += sizeof(WORD);
132 *(LPWORD)ptr = 0x0081;
133 ptr += sizeof(WORD);
134 ptr += MultiByteToWideChar(CP_ACP,0,text,-1,(LPWSTR)ptr,len) * sizeof(WCHAR);
135 *(LPWORD)ptr = 0x0000;
137 *template_out = tpl;
138 return len;
142 static int create_item(HDC hdc, const SANE_Option_Descriptor *opt,
143 INT id, LPDLGITEMTEMPLATEW *template_out, int y, int *cx, int* count)
145 LPDLGITEMTEMPLATEW tpl = NULL,rc = NULL;
146 WORD class = 0xffff;
147 DWORD styles = WS_VISIBLE;
148 LPBYTE ptr = NULL;
149 LPDLGITEMTEMPLATEW lead_static = NULL;
150 LPDLGITEMTEMPLATEW trail_edit = NULL;
151 DWORD leading_len = 0;
152 DWORD trail_len = 0;
153 DWORD local_len = 0;
154 LPCSTR title = NULL;
155 CHAR buffer[255];
156 int padding = 0;
157 int padding2 = 0;
158 int base_x = 0;
159 LONG base;
160 int ctl_cx = 0;
161 SIZE size;
163 GetTextExtentPoint32A(hdc,"X",1,&size);
164 base = GetDialogBaseUnits();
165 base_x = MulDiv(size.cx,4,LOWORD(base));
167 if (opt->type == SANE_TYPE_BOOL)
169 class = 0x0080; /* Button */
170 styles |= BS_AUTOCHECKBOX;
171 local_len += MultiByteToWideChar(CP_ACP,0,opt->title,-1,NULL,0);
172 local_len *= sizeof(WCHAR);
173 title = opt->title;
175 else if (opt->type == SANE_TYPE_INT)
177 SANE_Int i;
179 psane_control_option(activeDS.deviceHandle, id-ID_BASE,
180 SANE_ACTION_GET_VALUE, &i,NULL);
182 sprintf(buffer,"%i",i);
184 if (opt->constraint_type == SANE_CONSTRAINT_NONE)
186 class = 0x0081; /* Edit*/
187 styles |= ES_NUMBER;
188 title = buffer;
189 local_len += MultiByteToWideChar(CP_ACP,0,title,-1,NULL,0);
190 local_len *= sizeof(WCHAR);
192 else if (opt->constraint_type == SANE_CONSTRAINT_RANGE)
194 class = 0x0084; /* scroll */
195 ctl_cx = 10 * base_x;
196 trail_len += create_trailing_edit(hdc, &trail_edit, id +
197 ID_EDIT_BASE, y,buffer,TRUE);
199 else
201 class= 0x0085; /* Combo */
202 ctl_cx = 10 * base_x;
203 styles |= CBS_DROPDOWNLIST;
205 leading_len += create_leading_static(hdc, opt->title, &lead_static, y,
206 id+ID_STATIC_BASE);
208 else if (opt->type == SANE_TYPE_FIXED)
210 SANE_Fixed *i;
211 double dd;
213 i = HeapAlloc(GetProcessHeap(),0,opt->size*sizeof(SANE_Word));
215 psane_control_option(activeDS.deviceHandle, id-ID_BASE,
216 SANE_ACTION_GET_VALUE, i, NULL);
218 dd = SANE_UNFIX(*i);
219 sprintf(buffer,"%f",dd);
220 HeapFree(GetProcessHeap(),0,i);
222 if (opt->constraint_type == SANE_CONSTRAINT_NONE)
224 class = 0x0081; /* Edit */
225 title = buffer;
226 local_len += MultiByteToWideChar(CP_ACP,0,title,-1,NULL,0);
227 local_len *= sizeof(WCHAR);
229 else if (opt->constraint_type == SANE_CONSTRAINT_RANGE)
231 class= 0x0084; /* scroll */
232 ctl_cx = 10 * base_x;
233 trail_len += create_trailing_edit(hdc, &trail_edit, id +
234 ID_EDIT_BASE, y,buffer,FALSE);
236 else
238 class= 0x0085; /* Combo */
239 ctl_cx = 10 * base_x;
240 styles |= CBS_DROPDOWNLIST;
242 leading_len += create_leading_static(hdc, opt->title, &lead_static, y,
243 id+ID_STATIC_BASE);
245 else if (opt->type == SANE_TYPE_STRING)
247 if (opt->constraint_type == SANE_CONSTRAINT_NONE)
249 class = 0x0081; /* Edit*/
251 else
253 class= 0x0085; /* Combo */
254 ctl_cx = opt->size * base_x;
255 styles |= CBS_DROPDOWNLIST;
257 leading_len += create_leading_static(hdc, opt->title, &lead_static, y,
258 id+ID_STATIC_BASE);
259 psane_control_option(activeDS.deviceHandle, id-ID_BASE,
260 SANE_ACTION_GET_VALUE, buffer,NULL);
262 title = buffer;
263 local_len += MultiByteToWideChar(CP_ACP,0,title,-1,NULL,0);
264 local_len *= sizeof(WCHAR);
266 else if (opt->type == SANE_TYPE_BUTTON)
268 class = 0x0080; /* Button */
269 local_len += MultiByteToWideChar(CP_ACP,0,opt->title,-1,NULL,0);
270 local_len *= sizeof(WCHAR);
271 title = opt->title;
273 else if (opt->type == SANE_TYPE_GROUP)
275 class = 0x0080; /* Button */
276 styles |= BS_GROUPBOX;
277 local_len += MultiByteToWideChar(CP_ACP,0,opt->title,-1,NULL,0);
278 local_len *= sizeof(WCHAR);
279 title = opt->title;
282 local_len += sizeof(DLGITEMTEMPLATE);
283 if (title)
284 local_len += 3*sizeof(WORD);
285 else
286 local_len += 4*sizeof(WORD);
288 if (lead_static)
290 padding = leading_len % sizeof(DWORD);
291 rc = HeapReAlloc(GetProcessHeap(),0,lead_static,leading_len+local_len + padding);
292 tpl = (LPDLGITEMTEMPLATEW)((LPBYTE)rc + leading_len + padding);
294 else
295 rc = tpl = HeapAlloc(GetProcessHeap(),0,local_len);
297 tpl->style=styles;
298 tpl->dwExtendedStyle = 0;
299 if (lead_static)
300 tpl->x = lead_static->x + lead_static->cx + 1;
301 else if (opt->type == SANE_TYPE_GROUP)
302 tpl->x = 2;
303 else
304 tpl->x = 4;
305 tpl->y = y;
306 tpl->id = id;
308 if (title)
310 GetTextExtentPoint32A(hdc,title,lstrlenA(title),&size);
311 tpl->cx = size.cx;
312 tpl->cy = size.cy;
314 else
316 if (lead_static)
317 tpl->cy = lead_static->cy;
318 else
319 tpl->cy = 15;
321 if (!ctl_cx)
322 ctl_cx = 15;
324 tpl->cx = ctl_cx;
326 ptr = (LPBYTE)tpl + sizeof(DLGITEMTEMPLATE);
327 *(LPWORD)ptr = 0xffff;
328 ptr += sizeof(WORD);
329 *(LPWORD)ptr = class;
330 ptr += sizeof(WORD);
331 if (title)
333 ptr += MultiByteToWideChar(CP_ACP,0,title,-1,(LPWSTR)ptr,local_len) * sizeof(WCHAR);
335 else
337 *(LPWORD)ptr = 0x0000;
338 ptr += sizeof(WORD);
341 *((LPWORD)ptr) = 0x0000;
342 ptr += sizeof(WORD);
344 if (trail_edit)
346 trail_edit->x = tpl->cx + tpl->x + 2;
347 *cx = trail_edit->x + trail_edit->cx;
349 padding2 = (leading_len + local_len + padding)% sizeof(DWORD);
351 rc = HeapReAlloc(GetProcessHeap(),0,rc,leading_len+local_len + padding
352 +padding2+trail_len);
354 memcpy(((LPBYTE)rc) + leading_len + local_len + padding + padding2,
355 trail_edit,trail_len);
357 else
358 *cx = tpl->cx + tpl->x;
360 *template_out = rc;
361 if (leading_len)
362 *count = 2;
363 else
364 *count = 1;
366 if (trail_edit)
367 *count+=1;
369 return leading_len + local_len + padding + padding2 + trail_len;
373 static LPDLGTEMPLATEW create_options_page(HDC hdc, int *from_index,
374 SANE_Int optcount, BOOL split_tabs)
376 int i;
377 INT y = 2;
378 LPDLGTEMPLATEW tpl = NULL;
379 LPBYTE all_controls = NULL;
380 DWORD control_len = 0;
381 int max_cx = 0;
382 int group_max_cx = 0;
383 LPBYTE ptr;
384 int group_offset = -1;
385 INT control_count = 0;
387 for (i = *from_index; i < optcount; i++)
389 LPDLGITEMTEMPLATEW item_tpl = NULL;
390 const SANE_Option_Descriptor *opt;
391 int len;
392 int padding = 0;
393 int x;
394 int count;
395 int hold_for_group = 0;
397 opt = psane_get_option_descriptor(activeDS.deviceHandle, i);
398 if (!opt)
399 continue;
400 if (opt->type == SANE_TYPE_GROUP && split_tabs)
402 if (control_len > 0)
404 *from_index = i - 1;
405 goto exit;
407 else
409 *from_index = i;
410 return NULL;
413 if (!SANE_OPTION_IS_ACTIVE (opt->cap))
414 continue;
416 len = create_item(hdc, opt, ID_BASE + i, &item_tpl, y, &x, &count);
418 control_count += count;
420 if (!len)
422 continue;
425 hold_for_group = y;
426 y+= item_tpl->cy + 1;
427 max_cx = max(max_cx, x + 2);
428 group_max_cx = max(group_max_cx, x );
430 padding = len % sizeof(DWORD);
432 if (all_controls)
434 LPBYTE newone;
435 newone = HeapReAlloc(GetProcessHeap(),0,all_controls,
436 control_len + len + padding);
437 all_controls = newone;
438 memcpy(all_controls+control_len,item_tpl,len);
439 memset(all_controls+control_len+len,0xca,padding);
440 HeapFree(GetProcessHeap(),0,item_tpl);
442 else
444 if (!padding)
446 all_controls = (LPBYTE)item_tpl;
448 else
450 all_controls = HeapAlloc(GetProcessHeap(),0,len + padding);
451 memcpy(all_controls,item_tpl,len);
452 memset(all_controls+len,0xcb,padding);
453 HeapFree(GetProcessHeap(),0,item_tpl);
457 if (opt->type == SANE_TYPE_GROUP)
459 if (group_offset == -1)
461 group_offset = control_len;
462 group_max_cx = 0;
464 else
466 LPDLGITEMTEMPLATEW group =
467 (LPDLGITEMTEMPLATEW)(all_controls+group_offset);
469 group->cy = hold_for_group - group->y;
470 group->cx = group_max_cx;
472 group = (LPDLGITEMTEMPLATEW)(all_controls+control_len);
473 group->y += 2;
474 y+=2;
475 group_max_cx = 0;
476 group_offset = control_len;
480 control_len += len + padding;
483 if ( group_offset && !split_tabs )
485 LPDLGITEMTEMPLATEW group =
486 (LPDLGITEMTEMPLATEW)(all_controls+group_offset);
487 group->cy = y - group->y;
488 group->cx = group_max_cx;
489 y+=2;
492 *from_index = i-1;
493 exit:
495 tpl = HeapAlloc(GetProcessHeap(),0,sizeof(DLGTEMPLATE) + 3*sizeof(WORD) +
496 control_len);
498 tpl->style = WS_VISIBLE | WS_OVERLAPPEDWINDOW;
499 tpl->dwExtendedStyle = 0;
500 tpl->cdit = control_count;
501 tpl->x = 0;
502 tpl->y = 0;
503 tpl->cx = max_cx + 10;
504 tpl->cy = y + 10;
505 ptr = (LPBYTE)tpl + sizeof(DLGTEMPLATE);
506 *(LPWORD)ptr = 0x0000;
507 ptr+=sizeof(WORD);
508 *(LPWORD)ptr = 0x0000;
509 ptr+=sizeof(WORD);
510 *(LPWORD)ptr = 0x0000;
511 ptr+=sizeof(WORD);
512 memcpy(ptr,all_controls,control_len);
514 HeapFree(GetProcessHeap(),0,all_controls);
516 return tpl;
519 BOOL DoScannerUI(void)
521 HDC hdc;
522 PROPSHEETPAGEW psp[10];
523 int page_count= 0;
524 PROPSHEETHEADERW psh;
525 int index = 1;
526 SANE_Status rc;
527 SANE_Int optcount;
528 UINT psrc;
529 LPWSTR szCaption;
530 DWORD len;
532 hdc = GetDC(0);
534 memset(&psp,0,sizeof(psp));
535 rc = psane_control_option(activeDS.deviceHandle, 0, SANE_ACTION_GET_VALUE,
536 &optcount, NULL);
537 if (rc != SANE_STATUS_GOOD)
539 ERR("Unable to read number of options\n");
540 return FALSE;
543 while (index < optcount)
545 const SANE_Option_Descriptor *opt;
546 psp[page_count].u.pResource = create_options_page(hdc, &index,
547 optcount, TRUE);
548 opt = psane_get_option_descriptor(activeDS.deviceHandle, index);
550 if (opt->type == SANE_TYPE_GROUP)
552 LPWSTR title = NULL;
553 INT len;
555 len = MultiByteToWideChar(CP_ACP,0,opt->title,-1,NULL,0);
556 title = HeapAlloc(GetProcessHeap(),0,len * sizeof(WCHAR));
557 MultiByteToWideChar(CP_ACP,0,opt->title,-1,title,len);
559 psp[page_count].pszTitle = title;
562 if (psp[page_count].u.pResource)
564 psp[page_count].dwSize = sizeof(PROPSHEETPAGEW);
565 psp[page_count].dwFlags = PSP_DLGINDIRECT | PSP_USETITLE;
566 psp[page_count].hInstance = SANE_instance;
567 psp[page_count].pfnDlgProc = DialogProc;
568 psp[page_count].lParam = (LPARAM)&activeDS;
569 page_count ++;
572 index ++;
575 len = lstrlenA(activeDS.identity.Manufacturer)
576 + lstrlenA(activeDS.identity.ProductName) + 2;
577 szCaption = HeapAlloc(GetProcessHeap(),0,len *sizeof(WCHAR));
578 MultiByteToWideChar(CP_ACP,0,activeDS.identity.Manufacturer,-1,
579 szCaption,len);
580 szCaption[lstrlenA(activeDS.identity.Manufacturer)] = ' ';
581 MultiByteToWideChar(CP_ACP,0,activeDS.identity.ProductName,-1,
582 &szCaption[lstrlenA(activeDS.identity.Manufacturer)+1],len);
583 psh.dwSize = sizeof(PROPSHEETHEADERW);
584 psh.dwFlags = PSH_PROPSHEETPAGE|PSH_PROPTITLE|PSH_USECALLBACK;
585 psh.hwndParent = activeDS.hwndOwner;
586 psh.hInstance = SANE_instance;
587 psh.u.pszIcon = 0;
588 psh.pszCaption = szCaption;
589 psh.nPages = page_count;
590 psh.u2.nStartPage = 0;
591 psh.u3.ppsp = (LPCPROPSHEETPAGEW) &psp;
592 psh.pfnCallback = PropSheetProc;
594 psrc = PropertySheetW(&psh);
596 for(index = 0; index < page_count; index ++)
598 HeapFree(GetProcessHeap(),0,(LPBYTE)psp[index].u.pResource);
599 HeapFree(GetProcessHeap(),0,(LPBYTE)psp[index].pszTitle);
601 HeapFree(GetProcessHeap(),0,szCaption);
603 if (psrc == IDOK)
604 return TRUE;
605 else
606 return FALSE;
609 static void UpdateRelevantEdit(HWND hwnd, const SANE_Option_Descriptor *opt,
610 int index, int position)
612 WCHAR buffer[244];
613 HWND edit_w;
614 int len;
616 if (opt->type == SANE_TYPE_INT)
618 static const WCHAR formatW[] = {'%','i',0};
619 INT si;
621 if (opt->constraint.range->quant)
622 si = position * opt->constraint.range->quant;
623 else
624 si = position;
626 len = sprintfW( buffer, formatW, si );
628 else if (opt->type == SANE_TYPE_FIXED)
630 static const WCHAR formatW[] = {'%','f',0};
631 double s_quant, dd;
633 s_quant = SANE_UNFIX(opt->constraint.range->quant);
635 if (s_quant)
636 dd = position * s_quant;
637 else
638 dd = position * 0.01;
640 len = sprintfW( buffer, formatW, dd );
642 else return;
644 buffer[len++] = ' ';
645 LoadStringW( SANE_instance, opt->unit, buffer + len, sizeof(buffer)/sizeof(WCHAR) - len );
647 edit_w = GetDlgItem(hwnd,index+ID_BASE+ID_EDIT_BASE);
648 if (edit_w) SetWindowTextW(edit_w,buffer);
652 static BOOL UpdateSaneScrollOption(
653 const SANE_Option_Descriptor *opt, int index, DWORD position)
655 SANE_Status rc = SANE_STATUS_GOOD;
656 SANE_Int result = 0;
658 if (opt->type == SANE_TYPE_INT)
660 SANE_Int si;
662 if (opt->constraint.range->quant)
663 si = position * opt->constraint.range->quant;
664 else
665 si = position;
667 rc = psane_control_option (activeDS.deviceHandle,index,
668 SANE_ACTION_SET_VALUE, &si, &result);
671 else if (opt->type == SANE_TYPE_FIXED)
673 double s_quant, dd;
674 SANE_Fixed *sf;
676 s_quant = SANE_UNFIX(opt->constraint.range->quant);
678 if (s_quant)
679 dd = position * s_quant;
680 else
681 dd = position * 0.01;
683 sf = HeapAlloc(GetProcessHeap(),0,opt->size*sizeof(SANE_Word));
685 *sf = SANE_FIX(dd);
687 rc = psane_control_option (activeDS.deviceHandle,index,
688 SANE_ACTION_SET_VALUE, sf, &result);
690 HeapFree(GetProcessHeap(),0,sf);
693 if(rc == SANE_STATUS_GOOD)
695 if (result & SANE_INFO_RELOAD_OPTIONS ||
696 result & SANE_INFO_RELOAD_PARAMS || result & SANE_INFO_INEXACT)
697 return TRUE;
699 return FALSE;
702 static BOOL UpdateSaneBoolOption(int index, BOOL position)
704 SANE_Status rc = SANE_STATUS_GOOD;
705 SANE_Int result = 0;
706 SANE_Bool si;
708 si = position;
710 rc = psane_control_option (activeDS.deviceHandle,index,
711 SANE_ACTION_SET_VALUE, &si, &result);
713 if(rc == SANE_STATUS_GOOD)
715 if (result & SANE_INFO_RELOAD_OPTIONS ||
716 result & SANE_INFO_RELOAD_PARAMS || result & SANE_INFO_INEXACT)
717 return TRUE;
719 return FALSE;
722 static BOOL UpdateSaneStringOption(int index, SANE_String value)
724 SANE_Status rc = SANE_STATUS_GOOD;
725 SANE_Int result = 0;
727 rc = psane_control_option (activeDS.deviceHandle,index,
728 SANE_ACTION_SET_VALUE, value, &result);
730 if(rc == SANE_STATUS_GOOD)
732 if (result & SANE_INFO_RELOAD_OPTIONS ||
733 result & SANE_INFO_RELOAD_PARAMS || result & SANE_INFO_INEXACT)
734 return TRUE;
736 return FALSE;
739 static INT_PTR InitializeDialog(HWND hwnd)
741 SANE_Status rc;
742 SANE_Int optcount;
743 HWND control;
744 int i;
746 rc = psane_control_option(activeDS.deviceHandle, 0, SANE_ACTION_GET_VALUE,
747 &optcount, NULL);
748 if (rc != SANE_STATUS_GOOD)
750 ERR("Unable to read number of options\n");
751 return FALSE;
754 for ( i = 1; i < optcount; i++)
756 const SANE_Option_Descriptor *opt;
758 control = GetDlgItem(hwnd,i+ID_BASE);
760 if (!control)
761 continue;
763 opt = psane_get_option_descriptor(activeDS.deviceHandle, i);
765 TRACE("%i %s %i %i\n",i,opt->title,opt->type,opt->constraint_type);
767 if (!SANE_OPTION_IS_ACTIVE(opt->cap))
768 EnableWindow(control,FALSE);
769 else
770 EnableWindow(control,TRUE);
772 SendMessageA(control,CB_RESETCONTENT,0,0);
773 /* initialize values */
774 if (opt->type == SANE_TYPE_STRING && opt->constraint_type !=
775 SANE_CONSTRAINT_NONE)
777 int j = 0;
778 CHAR buffer[255];
779 while (opt->constraint.string_list[j]!=NULL)
781 SendMessageA(control,CB_ADDSTRING,0,
782 (LPARAM)opt->constraint.string_list[j]);
783 j++;
785 psane_control_option(activeDS.deviceHandle, i, SANE_ACTION_GET_VALUE, buffer,NULL);
786 SendMessageA(control,CB_SELECTSTRING,0,(LPARAM)buffer);
788 else if (opt->type == SANE_TYPE_BOOL)
790 SANE_Bool b;
791 psane_control_option(activeDS.deviceHandle, i,
792 SANE_ACTION_GET_VALUE, &b, NULL);
793 if (b)
794 SendMessageA(control,BM_SETCHECK,BST_CHECKED,0);
797 else if (opt->constraint_type == SANE_CONSTRAINT_RANGE)
799 if (opt->type == SANE_TYPE_INT)
801 SANE_Int si;
802 int min,max;
804 min = (SANE_Int)opt->constraint.range->min /
805 (((SANE_Int)opt->constraint.range->quant)?
806 (SANE_Int)opt->constraint.range->quant:1);
808 max = (SANE_Int)opt->constraint.range->max /
809 (((SANE_Int)opt->constraint.range->quant)
810 ?(SANE_Int)opt->constraint.range->quant:1);
812 SendMessageA(control,SBM_SETRANGE,min,max);
814 psane_control_option(activeDS.deviceHandle, i,
815 SANE_ACTION_GET_VALUE, &si,NULL);
816 if (opt->constraint.range->quant)
817 si = si / opt->constraint.range->quant;
819 SendMessageW(control,SBM_SETPOS, si, TRUE);
820 UpdateRelevantEdit(hwnd, opt, i, si);
822 else if (opt->type == SANE_TYPE_FIXED)
824 SANE_Fixed *sf;
826 double dd;
827 double s_min,s_max,s_quant;
828 INT pos;
829 int min,max;
831 s_min = SANE_UNFIX(opt->constraint.range->min);
832 s_max = SANE_UNFIX(opt->constraint.range->max);
833 s_quant = SANE_UNFIX(opt->constraint.range->quant);
835 if (s_quant)
837 min = (s_min / s_quant);
838 max = (s_max / s_quant);
840 else
842 min = s_min / 0.01;
843 max = s_max / 0.01;
846 SendMessageA(control,SBM_SETRANGE,min,max);
849 sf = HeapAlloc(GetProcessHeap(),0,opt->size*sizeof(SANE_Word));
850 psane_control_option(activeDS.deviceHandle, i,
851 SANE_ACTION_GET_VALUE, sf,NULL);
853 dd = SANE_UNFIX(*sf);
854 HeapFree(GetProcessHeap(),0,sf);
856 if (s_quant)
857 pos = (dd / s_quant);
858 else
859 pos = dd / 0.01;
861 SendMessageW(control, SBM_SETPOS, pos, TRUE);
863 UpdateRelevantEdit(hwnd, opt, i, pos);
868 return TRUE;
871 static INT_PTR ProcessScroll(HWND hwnd, WPARAM wParam, LPARAM lParam)
873 int index;
874 const SANE_Option_Descriptor *opt;
875 WORD scroll;
876 DWORD position;
878 index = GetDlgCtrlID((HWND)lParam)- ID_BASE;
879 if (index < 0)
880 return FALSE;
882 opt = psane_get_option_descriptor(activeDS.deviceHandle, index);
884 if (!opt)
885 return FALSE;
887 scroll = LOWORD(wParam);
889 switch (scroll)
891 case SB_THUMBTRACK:
892 case SB_THUMBPOSITION:
894 SCROLLINFO si;
895 si.cbSize = sizeof(SCROLLINFO);
896 si.fMask = SIF_TRACKPOS;
897 GetScrollInfo((HWND)lParam,SB_CTL, &si);
898 position = si.nTrackPos;
900 break;
901 case SB_LEFT:
902 case SB_LINELEFT:
903 case SB_PAGELEFT:
904 position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
905 position--;
906 break;
907 case SB_RIGHT:
908 case SB_LINERIGHT:
909 case SB_PAGERIGHT:
910 position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
911 position++;
912 break;
913 default:
914 position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
917 SendMessageW((HWND)lParam,SBM_SETPOS, position, TRUE);
918 position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
920 UpdateRelevantEdit(hwnd, opt, index, position);
921 if (UpdateSaneScrollOption(opt, index, position))
922 InitializeDialog(hwnd);
924 return TRUE;
928 static void ButtonClicked(HWND hwnd, INT id, HWND control)
930 int index;
931 const SANE_Option_Descriptor *opt;
933 index = id - ID_BASE;
934 if (index < 0)
935 return;
937 opt = psane_get_option_descriptor(activeDS.deviceHandle, index);
939 if (!opt)
940 return;
942 if (opt->type == SANE_TYPE_BOOL)
944 BOOL r = SendMessageW(control,BM_GETCHECK,0,0)==BST_CHECKED;
945 if (UpdateSaneBoolOption(index, r))
946 InitializeDialog(hwnd);
950 static void ComboChanged(HWND hwnd, INT id, HWND control)
952 int index;
953 int selection;
954 int len;
955 const SANE_Option_Descriptor *opt;
956 SANE_String value;
958 index = id - ID_BASE;
959 if (index < 0)
960 return;
962 opt = psane_get_option_descriptor(activeDS.deviceHandle, index);
964 if (!opt)
965 return;
967 selection = SendMessageW(control,CB_GETCURSEL,0,0);
968 len = SendMessageW(control,CB_GETLBTEXTLEN,selection,0);
970 len++;
971 value = HeapAlloc(GetProcessHeap(),0,len);
972 SendMessageA(control,CB_GETLBTEXT,selection,(LPARAM)value);
974 if (opt->type == SANE_TYPE_STRING)
976 if (UpdateSaneStringOption(index, value))
977 InitializeDialog(hwnd);
982 static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
984 switch (msg)
986 case WM_INITDIALOG:
987 return InitializeDialog(hwndDlg);
988 case WM_HSCROLL:
989 return ProcessScroll(hwndDlg, wParam, lParam);
990 case WM_NOTIFY:
992 LPPSHNOTIFY psn = (LPPSHNOTIFY)lParam;
993 switch (((NMHDR*)lParam)->code)
995 case PSN_APPLY:
996 if (psn->lParam == TRUE)
998 activeDS.currentState = 6;
999 activeDS.pendingEvent.TWMessage = MSG_XFERREADY;
1001 break;
1002 case PSN_QUERYCANCEL:
1003 activeDS.pendingEvent.TWMessage = MSG_CLOSEDSREQ;
1004 break;
1005 case PSN_SETACTIVE:
1006 InitializeDialog(hwndDlg);
1007 break;
1010 case WM_COMMAND:
1012 switch (HIWORD(wParam))
1014 case BN_CLICKED:
1015 ButtonClicked(hwndDlg,LOWORD(wParam),
1016 (HWND)lParam);
1017 break;
1018 case CBN_SELCHANGE:
1019 ComboChanged(hwndDlg,LOWORD(wParam),
1020 (HWND)lParam);
1025 return FALSE;
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");
1036 return TRUE;
1040 static INT_PTR CALLBACK ScanningProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1042 return FALSE;
1045 HWND ScanningDialogBox(HWND dialog, LONG progress)
1047 if (!dialog)
1048 dialog = CreateDialogW(SANE_instance,
1049 (LPWSTR)MAKEINTRESOURCE(IDD_DIALOG1), NULL, ScanningProc);
1051 if (progress == -1)
1053 EndDialog(dialog,0);
1054 return NULL;
1057 RedrawWindow(dialog,NULL,NULL,
1058 RDW_INTERNALPAINT|RDW_UPDATENOW|RDW_ALLCHILDREN);
1060 return dialog;
1063 #else /* SONAME_LIBSANE */
1065 BOOL DoScannerUI(void)
1067 return FALSE;
1070 #endif /* SONAME_LIBSANE */