msvcp90: Remove MSVCP_bool type.
[wine.git] / dlls / sane.ds / ui.c
blob8a2890cb30df016e240ac4a7938c3181dd0b6c14
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
29 #include "sane_i.h"
30 #include "winuser.h"
31 #include "winnls.h"
32 #include "wingdi.h"
33 #include "prsht.h"
34 #include "wine/debug.h"
35 #include "resource.h"
36 #include "wine/unicode.h"
38 #ifdef SONAME_LIBSANE
40 WINE_DEFAULT_DEBUG_CHANNEL(twain);
42 #define ID_BASE 0x100
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;
53 INT len;
54 SIZE size;
55 LPBYTE ptr;
56 LONG base;
58 *template_out = NULL;
60 if (!text)
61 return 0;
63 base = GetDialogBaseUnits();
65 len = MultiByteToWideChar(CP_ACP,0,text,-1,NULL,0);
66 len *= sizeof(WCHAR);
67 len += sizeof(DLGITEMTEMPLATE);
68 len += 3*sizeof(WORD);
70 tpl = HeapAlloc(GetProcessHeap(),0,len);
71 tpl->style=WS_VISIBLE;
72 tpl->dwExtendedStyle = 0;
73 tpl->x = 4;
74 tpl->y = y;
75 tpl->id = ID_BASE;
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;
83 ptr += sizeof(WORD);
84 *(LPWORD)ptr = 0x0082;
85 ptr += sizeof(WORD);
86 ptr += MultiByteToWideChar(CP_ACP,0,text,-1,(LPWSTR)ptr,len) * sizeof(WCHAR);
87 *(LPWORD)ptr = 0x0000;
89 *template_out = tpl;
90 return len;
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;
97 INT len;
98 LPBYTE ptr;
99 SIZE size;
100 LONG base;
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;
114 tpl->x = 1;
115 tpl->y = y;
116 tpl->id = id;
118 if (is_int)
119 GetTextExtentPoint32A(hdc,int_base,lstrlenA(int_base),&size);
120 else
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;
128 ptr += sizeof(WORD);
129 *(LPWORD)ptr = 0x0081;
130 ptr += sizeof(WORD);
131 ptr += MultiByteToWideChar(CP_ACP,0,text,-1,(LPWSTR)ptr,len) * sizeof(WCHAR);
132 *(LPWORD)ptr = 0x0000;
134 *template_out = tpl;
135 return len;
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;
143 WORD class = 0xffff;
144 DWORD styles = WS_VISIBLE;
145 LPBYTE ptr = NULL;
146 LPDLGITEMTEMPLATEW lead_static = NULL;
147 LPDLGITEMTEMPLATEW trail_edit = NULL;
148 DWORD leading_len = 0;
149 DWORD trail_len = 0;
150 DWORD local_len = 0;
151 LPCSTR title = NULL;
152 CHAR buffer[255];
153 int padding = 0;
154 int padding2 = 0;
155 int base_x = 0;
156 LONG base;
157 int ctl_cx = 0;
158 SIZE size;
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);
170 title = opt->title;
172 else if (opt->type == SANE_TYPE_INT)
174 SANE_Int i;
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*/
184 styles |= ES_NUMBER;
185 title = buffer;
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);
196 else
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,
203 id+ID_STATIC_BASE);
205 else if (opt->type == SANE_TYPE_FIXED)
207 SANE_Fixed *i;
208 double dd;
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);
215 dd = SANE_UNFIX(*i);
216 sprintf(buffer,"%f",dd);
217 HeapFree(GetProcessHeap(),0,i);
219 if (opt->constraint_type == SANE_CONSTRAINT_NONE)
221 class = 0x0081; /* Edit */
222 title = buffer;
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);
233 else
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,
240 id+ID_STATIC_BASE);
242 else if (opt->type == SANE_TYPE_STRING)
244 if (opt->constraint_type == SANE_CONSTRAINT_NONE)
246 class = 0x0081; /* Edit*/
248 else
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,
255 id+ID_STATIC_BASE);
256 psane_control_option(activeDS.deviceHandle, id-ID_BASE,
257 SANE_ACTION_GET_VALUE, buffer,NULL);
259 title = buffer;
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);
268 title = opt->title;
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);
276 title = opt->title;
279 local_len += sizeof(DLGITEMTEMPLATE);
280 if (title)
281 local_len += 3*sizeof(WORD);
282 else
283 local_len += 4*sizeof(WORD);
285 if (lead_static)
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);
291 else
292 rc = tpl = HeapAlloc(GetProcessHeap(),0,local_len);
294 tpl->style=styles;
295 tpl->dwExtendedStyle = 0;
296 if (lead_static)
297 tpl->x = lead_static->x + lead_static->cx + 1;
298 else if (opt->type == SANE_TYPE_GROUP)
299 tpl->x = 2;
300 else
301 tpl->x = 4;
302 tpl->y = y;
303 tpl->id = id;
305 if (title)
307 GetTextExtentPoint32A(hdc,title,lstrlenA(title),&size);
308 tpl->cx = size.cx;
309 tpl->cy = size.cy;
311 else
313 if (lead_static)
314 tpl->cy = lead_static->cy;
315 else
316 tpl->cy = 15;
318 if (!ctl_cx)
319 ctl_cx = 15;
321 tpl->cx = ctl_cx;
323 ptr = (LPBYTE)tpl + sizeof(DLGITEMTEMPLATE);
324 *(LPWORD)ptr = 0xffff;
325 ptr += sizeof(WORD);
326 *(LPWORD)ptr = class;
327 ptr += sizeof(WORD);
328 if (title)
330 ptr += MultiByteToWideChar(CP_ACP,0,title,-1,(LPWSTR)ptr,local_len) * sizeof(WCHAR);
332 else
334 *(LPWORD)ptr = 0x0000;
335 ptr += sizeof(WORD);
338 *((LPWORD)ptr) = 0x0000;
339 ptr += sizeof(WORD);
341 if (trail_edit)
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);
354 else
355 *cx = tpl->cx + tpl->x;
357 *template_out = rc;
358 if (leading_len)
359 *count = 2;
360 else
361 *count = 1;
363 if (trail_edit)
364 *count+=1;
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)
373 int i;
374 INT y = 2;
375 LPDLGTEMPLATEW tpl = NULL;
376 LPBYTE all_controls = NULL;
377 DWORD control_len = 0;
378 int max_cx = 0;
379 int group_max_cx = 0;
380 LPBYTE ptr;
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;
388 int len;
389 int padding = 0;
390 int x;
391 int count;
392 int hold_for_group = 0;
394 opt = psane_get_option_descriptor(activeDS.deviceHandle, i);
395 if (!opt)
396 continue;
397 if (opt->type == SANE_TYPE_GROUP && split_tabs)
399 if (control_len > 0)
401 *from_index = i - 1;
402 goto exit;
404 else
406 *from_index = i;
407 return NULL;
410 if (!SANE_OPTION_IS_ACTIVE (opt->cap))
411 continue;
413 len = create_item(hdc, opt, ID_BASE + i, &item_tpl, y, &x, &count);
415 control_count += count;
417 if (!len)
419 continue;
422 hold_for_group = y;
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);
429 if (all_controls)
431 LPBYTE newone;
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);
439 else
441 if (!padding)
443 all_controls = (LPBYTE)item_tpl;
445 else
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;
459 group_max_cx = 0;
461 else
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);
470 group->y += 2;
471 y+=2;
472 group_max_cx = 0;
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;
486 y+=2;
489 *from_index = i-1;
490 exit:
492 tpl = HeapAlloc(GetProcessHeap(),0,sizeof(DLGTEMPLATE) + 3*sizeof(WORD) +
493 control_len);
495 tpl->style = WS_VISIBLE | WS_OVERLAPPEDWINDOW;
496 tpl->dwExtendedStyle = 0;
497 tpl->cdit = control_count;
498 tpl->x = 0;
499 tpl->y = 0;
500 tpl->cx = max_cx + 10;
501 tpl->cy = y + 10;
502 ptr = (LPBYTE)tpl + sizeof(DLGTEMPLATE);
503 *(LPWORD)ptr = 0x0000;
504 ptr+=sizeof(WORD);
505 *(LPWORD)ptr = 0x0000;
506 ptr+=sizeof(WORD);
507 *(LPWORD)ptr = 0x0000;
508 ptr+=sizeof(WORD);
509 memcpy(ptr,all_controls,control_len);
511 HeapFree(GetProcessHeap(),0,all_controls);
513 return tpl;
516 BOOL DoScannerUI(void)
518 HDC hdc;
519 PROPSHEETPAGEW psp[10];
520 int page_count= 0;
521 PROPSHEETHEADERW psh;
522 int index = 1;
523 SANE_Status rc;
524 SANE_Int optcount;
525 UINT psrc;
526 LPWSTR szCaption;
527 DWORD len;
529 hdc = GetDC(0);
531 memset(psp,0,sizeof(psp));
532 rc = psane_control_option(activeDS.deviceHandle, 0, SANE_ACTION_GET_VALUE,
533 &optcount, NULL);
534 if (rc != SANE_STATUS_GOOD)
536 ERR("Unable to read number of options\n");
537 return FALSE;
540 while (index < optcount)
542 const SANE_Option_Descriptor *opt;
543 psp[page_count].u.pResource = create_options_page(hdc, &index,
544 optcount, TRUE);
545 opt = psane_get_option_descriptor(activeDS.deviceHandle, index);
547 if (opt->type == SANE_TYPE_GROUP)
549 LPWSTR title = NULL;
550 INT len;
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;
566 page_count ++;
569 index ++;
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,
576 szCaption,len);
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;
584 psh.u.pszIcon = 0;
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);
600 if (psrc == IDOK)
601 return TRUE;
602 else
603 return FALSE;
606 static void UpdateRelevantEdit(HWND hwnd, const SANE_Option_Descriptor *opt,
607 int index, int position)
609 WCHAR buffer[244];
610 HWND edit_w;
611 int len;
613 if (opt->type == SANE_TYPE_INT)
615 static const WCHAR formatW[] = {'%','i',0};
616 INT si;
618 if (opt->constraint.range->quant)
619 si = position * opt->constraint.range->quant;
620 else
621 si = position;
623 len = sprintfW( buffer, formatW, si );
625 else if (opt->type == SANE_TYPE_FIXED)
627 static const WCHAR formatW[] = {'%','f',0};
628 double s_quant, dd;
630 s_quant = SANE_UNFIX(opt->constraint.range->quant);
632 if (s_quant)
633 dd = position * s_quant;
634 else
635 dd = position * 0.01;
637 len = sprintfW( buffer, formatW, dd );
639 else return;
641 buffer[len++] = ' ';
642 LoadStringW( SANE_instance, opt->unit, buffer + len, ARRAY_SIZE( buffer ) - 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;
653 SANE_Int result = 0;
655 if (opt->type == SANE_TYPE_INT)
657 SANE_Int si;
659 if (opt->constraint.range->quant)
660 si = position * opt->constraint.range->quant;
661 else
662 si = position;
664 rc = psane_control_option (activeDS.deviceHandle,index,
665 SANE_ACTION_SET_VALUE, &si, &result);
668 else if (opt->type == SANE_TYPE_FIXED)
670 double s_quant, dd;
671 SANE_Fixed *sf;
673 s_quant = SANE_UNFIX(opt->constraint.range->quant);
675 if (s_quant)
676 dd = position * s_quant;
677 else
678 dd = position * 0.01;
680 sf = HeapAlloc(GetProcessHeap(),0,opt->size*sizeof(SANE_Word));
682 *sf = SANE_FIX(dd);
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)
694 return TRUE;
696 return FALSE;
699 static BOOL UpdateSaneBoolOption(int index, BOOL position)
701 SANE_Status rc = SANE_STATUS_GOOD;
702 SANE_Int result = 0;
703 SANE_Bool si;
705 si = position;
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)
714 return TRUE;
716 return FALSE;
719 static BOOL UpdateSaneIntOption(int index, SANE_Int value)
721 SANE_Status rc = SANE_STATUS_GOOD;
722 SANE_Int result = 0;
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)
731 return TRUE;
733 return FALSE;
736 static BOOL UpdateSaneStringOption(int index, SANE_String value)
738 SANE_Status rc = SANE_STATUS_GOOD;
739 SANE_Int result = 0;
741 rc = psane_control_option (activeDS.deviceHandle,index,
742 SANE_ACTION_SET_VALUE, value, &result);
744 if(rc == SANE_STATUS_GOOD)
746 if (result & SANE_INFO_RELOAD_OPTIONS ||
747 result & SANE_INFO_RELOAD_PARAMS || result & SANE_INFO_INEXACT)
748 return TRUE;
750 return FALSE;
753 static INT_PTR InitializeDialog(HWND hwnd)
755 SANE_Status rc;
756 SANE_Int optcount;
757 HWND control;
758 int i;
760 rc = psane_control_option(activeDS.deviceHandle, 0, SANE_ACTION_GET_VALUE,
761 &optcount, NULL);
762 if (rc != SANE_STATUS_GOOD)
764 ERR("Unable to read number of options\n");
765 return FALSE;
768 for ( i = 1; i < optcount; i++)
770 const SANE_Option_Descriptor *opt;
772 control = GetDlgItem(hwnd,i+ID_BASE);
774 if (!control)
775 continue;
777 opt = psane_get_option_descriptor(activeDS.deviceHandle, i);
779 TRACE("%i %s %i %i\n",i,opt->title,opt->type,opt->constraint_type);
781 if (!SANE_OPTION_IS_ACTIVE(opt->cap))
782 EnableWindow(control,FALSE);
783 else
784 EnableWindow(control,TRUE);
786 SendMessageA(control,CB_RESETCONTENT,0,0);
787 /* initialize values */
788 if (opt->type == SANE_TYPE_STRING && opt->constraint_type !=
789 SANE_CONSTRAINT_NONE)
791 int j = 0;
792 CHAR buffer[255];
793 while (opt->constraint.string_list[j]!=NULL)
795 SendMessageA(control,CB_ADDSTRING,0,
796 (LPARAM)opt->constraint.string_list[j]);
797 j++;
799 psane_control_option(activeDS.deviceHandle, i, SANE_ACTION_GET_VALUE, buffer,NULL);
800 SendMessageA(control,CB_SELECTSTRING,0,(LPARAM)buffer);
802 else if (opt->type == SANE_TYPE_BOOL)
804 SANE_Bool b;
805 psane_control_option(activeDS.deviceHandle, i,
806 SANE_ACTION_GET_VALUE, &b, NULL);
807 if (b)
808 SendMessageA(control,BM_SETCHECK,BST_CHECKED,0);
811 else if (opt->type == SANE_TYPE_INT &&
812 opt->constraint_type == SANE_CONSTRAINT_WORD_LIST)
814 int j, count = opt->constraint.word_list[0];
815 CHAR buffer[16];
816 SANE_Int val;
817 for (j=1; j<=count; j++)
819 sprintf(buffer, "%d", opt->constraint.word_list[j]);
820 SendMessageA(control, CB_ADDSTRING, 0, (LPARAM)buffer);
822 psane_control_option(activeDS.deviceHandle, i, SANE_ACTION_GET_VALUE, &val, NULL);
823 sprintf(buffer, "%d", val);
824 SendMessageA(control,CB_SELECTSTRING,0,(LPARAM)buffer);
826 else if (opt->constraint_type == SANE_CONSTRAINT_RANGE)
828 if (opt->type == SANE_TYPE_INT)
830 SANE_Int si;
831 int min,max;
833 min = (SANE_Int)opt->constraint.range->min /
834 (((SANE_Int)opt->constraint.range->quant)?
835 (SANE_Int)opt->constraint.range->quant:1);
837 max = (SANE_Int)opt->constraint.range->max /
838 (((SANE_Int)opt->constraint.range->quant)
839 ?(SANE_Int)opt->constraint.range->quant:1);
841 SendMessageA(control,SBM_SETRANGE,min,max);
843 psane_control_option(activeDS.deviceHandle, i,
844 SANE_ACTION_GET_VALUE, &si,NULL);
845 if (opt->constraint.range->quant)
846 si = si / opt->constraint.range->quant;
848 SendMessageW(control,SBM_SETPOS, si, TRUE);
849 UpdateRelevantEdit(hwnd, opt, i, si);
851 else if (opt->type == SANE_TYPE_FIXED)
853 SANE_Fixed *sf;
855 double dd;
856 double s_min,s_max,s_quant;
857 INT pos;
858 int min,max;
860 s_min = SANE_UNFIX(opt->constraint.range->min);
861 s_max = SANE_UNFIX(opt->constraint.range->max);
862 s_quant = SANE_UNFIX(opt->constraint.range->quant);
864 if (s_quant)
866 min = (s_min / s_quant);
867 max = (s_max / s_quant);
869 else
871 min = s_min / 0.01;
872 max = s_max / 0.01;
875 SendMessageA(control,SBM_SETRANGE,min,max);
878 sf = HeapAlloc(GetProcessHeap(),0,opt->size*sizeof(SANE_Word));
879 psane_control_option(activeDS.deviceHandle, i,
880 SANE_ACTION_GET_VALUE, sf,NULL);
882 dd = SANE_UNFIX(*sf);
883 HeapFree(GetProcessHeap(),0,sf);
885 /* Note that conversion of float -> SANE_Fixed is lossy;
886 * and when you truncate it into an integer, you can get
887 * unfortunate results. This calculation attempts
888 * to mitigate that harm */
889 if (s_quant)
890 pos = ((dd + (s_quant/2.0)) / s_quant);
891 else
892 pos = (dd + 0.005) / 0.01;
894 SendMessageW(control, SBM_SETPOS, pos, TRUE);
896 UpdateRelevantEdit(hwnd, opt, i, pos);
901 return TRUE;
904 static INT_PTR ProcessScroll(HWND hwnd, WPARAM wParam, LPARAM lParam)
906 int index;
907 const SANE_Option_Descriptor *opt;
908 WORD scroll;
909 DWORD position;
911 index = GetDlgCtrlID((HWND)lParam)- ID_BASE;
912 if (index < 0)
913 return FALSE;
915 opt = psane_get_option_descriptor(activeDS.deviceHandle, index);
917 if (!opt)
918 return FALSE;
920 scroll = LOWORD(wParam);
922 switch (scroll)
924 case SB_THUMBTRACK:
925 case SB_THUMBPOSITION:
927 SCROLLINFO si;
928 si.cbSize = sizeof(SCROLLINFO);
929 si.fMask = SIF_TRACKPOS;
930 GetScrollInfo((HWND)lParam,SB_CTL, &si);
931 position = si.nTrackPos;
933 break;
934 case SB_LEFT:
935 case SB_LINELEFT:
936 case SB_PAGELEFT:
937 position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
938 position--;
939 break;
940 case SB_RIGHT:
941 case SB_LINERIGHT:
942 case SB_PAGERIGHT:
943 position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
944 position++;
945 break;
946 default:
947 position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
950 SendMessageW((HWND)lParam,SBM_SETPOS, position, TRUE);
951 position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
953 UpdateRelevantEdit(hwnd, opt, index, position);
954 if (UpdateSaneScrollOption(opt, index, position))
955 InitializeDialog(hwnd);
957 return TRUE;
961 static void ButtonClicked(HWND hwnd, INT id, HWND control)
963 int index;
964 const SANE_Option_Descriptor *opt;
966 index = id - ID_BASE;
967 if (index < 0)
968 return;
970 opt = psane_get_option_descriptor(activeDS.deviceHandle, index);
972 if (!opt)
973 return;
975 if (opt->type == SANE_TYPE_BOOL)
977 BOOL r = SendMessageW(control,BM_GETCHECK,0,0)==BST_CHECKED;
978 if (UpdateSaneBoolOption(index, r))
979 InitializeDialog(hwnd);
983 static void ComboChanged(HWND hwnd, INT id, HWND control)
985 int index;
986 int selection;
987 int len;
988 const SANE_Option_Descriptor *opt;
989 SANE_String value;
991 index = id - ID_BASE;
992 if (index < 0)
993 return;
995 opt = psane_get_option_descriptor(activeDS.deviceHandle, index);
997 if (!opt)
998 return;
1000 selection = SendMessageW(control,CB_GETCURSEL,0,0);
1001 len = SendMessageW(control,CB_GETLBTEXTLEN,selection,0);
1003 len++;
1004 value = HeapAlloc(GetProcessHeap(),0,len);
1005 SendMessageA(control,CB_GETLBTEXT,selection,(LPARAM)value);
1007 if (opt->type == SANE_TYPE_STRING)
1009 if (UpdateSaneStringOption(index, value))
1010 InitializeDialog(hwnd);
1012 else if (opt->type == SANE_TYPE_INT)
1014 if (UpdateSaneIntOption(index, atoi(value)))
1015 InitializeDialog(hwnd);
1020 static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
1022 switch (msg)
1024 case WM_INITDIALOG:
1025 return InitializeDialog(hwndDlg);
1026 case WM_HSCROLL:
1027 return ProcessScroll(hwndDlg, wParam, lParam);
1028 case WM_NOTIFY:
1030 LPPSHNOTIFY psn = (LPPSHNOTIFY)lParam;
1031 switch (((NMHDR*)lParam)->code)
1033 case PSN_APPLY:
1034 if (psn->lParam)
1036 activeDS.currentState = 6;
1037 SANE_Notify(MSG_XFERREADY);
1039 break;
1040 case PSN_QUERYCANCEL:
1041 SANE_Notify(MSG_CLOSEDSREQ);
1042 break;
1043 case PSN_SETACTIVE:
1044 InitializeDialog(hwndDlg);
1045 break;
1047 break;
1049 case WM_COMMAND:
1050 switch (HIWORD(wParam))
1052 case BN_CLICKED:
1053 ButtonClicked(hwndDlg,LOWORD(wParam), (HWND)lParam);
1054 break;
1055 case CBN_SELCHANGE:
1056 ComboChanged(hwndDlg,LOWORD(wParam), (HWND)lParam);
1060 return FALSE;
1063 static int CALLBACK PropSheetProc(HWND hwnd, UINT msg, LPARAM lParam)
1065 if (msg == PSCB_INITIALIZED)
1067 /* rename OK button to Scan */
1068 HWND scan = GetDlgItem(hwnd,IDOK);
1069 SetWindowTextA(scan,"Scan");
1071 return TRUE;
1075 static INT_PTR CALLBACK ScanningProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1077 return FALSE;
1080 HWND ScanningDialogBox(HWND dialog, LONG progress)
1082 if (!dialog)
1083 dialog = CreateDialogW(SANE_instance,
1084 (LPWSTR)MAKEINTRESOURCE(IDD_DIALOG1), NULL, ScanningProc);
1086 if (progress == -1)
1088 EndDialog(dialog,0);
1089 return NULL;
1092 RedrawWindow(dialog,NULL,NULL,
1093 RDW_INTERNALPAINT|RDW_UPDATENOW|RDW_ALLCHILDREN);
1095 return dialog;
1098 #else /* SONAME_LIBSANE */
1100 BOOL DoScannerUI(void)
1102 return FALSE;
1105 #endif /* SONAME_LIBSANE */