appwiz.cpl: Fix compilation on systems that don't support nameless unions.
[wine.git] / dlls / sane.ds / ui.c
blob83006c5195cb1935551784ea822eaa5d26a2684a
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"
40 #ifdef SONAME_LIBSANE
42 WINE_DEFAULT_DEBUG_CHANNEL(twain);
44 #define ID_BASE 0x100
45 #define ID_EDIT_BASE 0x1000
46 #define ID_STATIC_BASE 0x2000
48 static INT_PTR CALLBACK DialogProc (HWND , UINT , WPARAM , LPARAM );
49 static INT CALLBACK PropSheetProc(HWND, UINT,LPARAM);
51 static int create_leading_static(HDC hdc, LPCSTR text,
52 LPDLGITEMTEMPLATEW* template_out, int y, int id)
54 LPDLGITEMTEMPLATEW tpl = NULL;
55 INT len;
56 SIZE size;
57 LPBYTE ptr;
58 LONG base;
60 *template_out = NULL;
62 if (!text)
63 return 0;
65 base = GetDialogBaseUnits();
67 len = MultiByteToWideChar(CP_ACP,0,text,-1,NULL,0);
68 len *= sizeof(WCHAR);
69 len += sizeof(DLGITEMTEMPLATE);
70 len += 3*sizeof(WORD);
72 tpl = HeapAlloc(GetProcessHeap(),0,len);
73 tpl->style=WS_VISIBLE;
74 tpl->dwExtendedStyle = 0;
75 tpl->x = 4;
76 tpl->y = y;
77 tpl->id = ID_BASE;
79 GetTextExtentPoint32A(hdc,text,lstrlenA(text),&size);
81 tpl->cx = MulDiv(size.cx,4,LOWORD(base));
82 tpl->cy = MulDiv(size.cy,8,HIWORD(base)) * 2;
83 ptr = (LPBYTE)tpl + sizeof(DLGITEMTEMPLATE);
84 *(LPWORD)ptr = 0xffff;
85 ptr += sizeof(WORD);
86 *(LPWORD)ptr = 0x0082;
87 ptr += sizeof(WORD);
88 ptr += MultiByteToWideChar(CP_ACP,0,text,-1,(LPWSTR)ptr,len) * sizeof(WCHAR);
89 *(LPWORD)ptr = 0x0000;
91 *template_out = tpl;
92 return len;
95 static int create_trailing_edit(HDC hdc, LPDLGITEMTEMPLATEW* template_out, int id,
96 int y, LPCSTR text,BOOL is_int)
98 LPDLGITEMTEMPLATEW tpl = NULL;
99 INT len;
100 LPBYTE ptr;
101 SIZE size;
102 LONG base;
103 static const char int_base[] = "0000 xxx";
104 static const char float_base[] = "0000.0000 xxx";
106 base = GetDialogBaseUnits();
108 len = MultiByteToWideChar(CP_ACP,0,text,-1,NULL,0);
109 len *= sizeof(WCHAR);
110 len += sizeof(DLGITEMTEMPLATE);
111 len += 3*sizeof(WORD);
113 tpl = HeapAlloc(GetProcessHeap(),0,len);
114 tpl->style=WS_VISIBLE|ES_READONLY|WS_BORDER;
115 tpl->dwExtendedStyle = 0;
116 tpl->x = 1;
117 tpl->y = y;
118 tpl->id = id;
120 if (is_int)
121 GetTextExtentPoint32A(hdc,int_base,lstrlenA(int_base),&size);
122 else
123 GetTextExtentPoint32A(hdc,float_base,lstrlenA(float_base),&size);
125 tpl->cx = MulDiv(size.cx*2,4,LOWORD(base));
126 tpl->cy = MulDiv(size.cy,8,HIWORD(base)) * 2;
128 ptr = (LPBYTE)tpl + sizeof(DLGITEMTEMPLATE);
129 *(LPWORD)ptr = 0xffff;
130 ptr += sizeof(WORD);
131 *(LPWORD)ptr = 0x0081;
132 ptr += sizeof(WORD);
133 ptr += MultiByteToWideChar(CP_ACP,0,text,-1,(LPWSTR)ptr,len) * sizeof(WCHAR);
134 *(LPWORD)ptr = 0x0000;
136 *template_out = tpl;
137 return len;
141 static int create_item(HDC hdc, const SANE_Option_Descriptor *opt,
142 INT id, LPDLGITEMTEMPLATEW *template_out, int y, int *cx, int* count)
144 LPDLGITEMTEMPLATEW tpl = NULL,rc = NULL;
145 WORD class = 0xffff;
146 DWORD styles = WS_VISIBLE;
147 LPBYTE ptr = NULL;
148 LPDLGITEMTEMPLATEW lead_static = NULL;
149 LPDLGITEMTEMPLATEW trail_edit = NULL;
150 DWORD leading_len = 0;
151 DWORD trail_len = 0;
152 DWORD local_len = 0;
153 LPCSTR title = NULL;
154 CHAR buffer[255];
155 int padding = 0;
156 int padding2 = 0;
157 int base_x = 0;
158 LONG base;
159 int ctl_cx = 0;
160 SIZE size;
162 GetTextExtentPoint32A(hdc,"X",1,&size);
163 base = GetDialogBaseUnits();
164 base_x = MulDiv(size.cx,4,LOWORD(base));
166 if (opt->type == SANE_TYPE_BOOL)
168 class = 0x0080; /* Button */
169 styles |= BS_AUTOCHECKBOX;
170 local_len += MultiByteToWideChar(CP_ACP,0,opt->title,-1,NULL,0);
171 local_len *= sizeof(WCHAR);
172 title = opt->title;
174 else if (opt->type == SANE_TYPE_INT)
176 SANE_Int i;
178 psane_control_option(activeDS.deviceHandle, id-ID_BASE,
179 SANE_ACTION_GET_VALUE, &i,NULL);
181 sprintf(buffer,"%i",i);
183 if (opt->constraint_type == SANE_CONSTRAINT_NONE)
185 class = 0x0081; /* Edit*/
186 styles |= ES_NUMBER;
187 title = buffer;
188 local_len += MultiByteToWideChar(CP_ACP,0,title,-1,NULL,0);
189 local_len *= sizeof(WCHAR);
191 else if (opt->constraint_type == SANE_CONSTRAINT_RANGE)
193 class = 0x0084; /* scroll */
194 ctl_cx = 10 * base_x;
195 trail_len += create_trailing_edit(hdc, &trail_edit, id +
196 ID_EDIT_BASE, y,buffer,TRUE);
198 else
200 class= 0x0085; /* Combo */
201 ctl_cx = 10 * base_x;
202 styles |= CBS_DROPDOWNLIST;
204 leading_len += create_leading_static(hdc, opt->title, &lead_static, y,
205 id+ID_STATIC_BASE);
207 else if (opt->type == SANE_TYPE_FIXED)
209 SANE_Fixed *i;
210 double dd;
212 i = HeapAlloc(GetProcessHeap(),0,opt->size*sizeof(SANE_Word));
214 psane_control_option(activeDS.deviceHandle, id-ID_BASE,
215 SANE_ACTION_GET_VALUE, i, NULL);
217 dd = SANE_UNFIX(*i);
218 sprintf(buffer,"%f",dd);
219 HeapFree(GetProcessHeap(),0,i);
221 if (opt->constraint_type == SANE_CONSTRAINT_NONE)
223 class = 0x0081; /* Edit */
224 title = buffer;
225 local_len += MultiByteToWideChar(CP_ACP,0,title,-1,NULL,0);
226 local_len *= sizeof(WCHAR);
228 else if (opt->constraint_type == SANE_CONSTRAINT_RANGE)
230 class= 0x0084; /* scroll */
231 ctl_cx = 10 * base_x;
232 trail_len += create_trailing_edit(hdc, &trail_edit, id +
233 ID_EDIT_BASE, y,buffer,FALSE);
235 else
237 class= 0x0085; /* Combo */
238 ctl_cx = 10 * base_x;
239 styles |= CBS_DROPDOWNLIST;
241 leading_len += create_leading_static(hdc, opt->title, &lead_static, y,
242 id+ID_STATIC_BASE);
244 else if (opt->type == SANE_TYPE_STRING)
246 if (opt->constraint_type == SANE_CONSTRAINT_NONE)
248 class = 0x0081; /* Edit*/
250 else
252 class= 0x0085; /* Combo */
253 ctl_cx = opt->size * base_x;
254 styles |= CBS_DROPDOWNLIST;
256 leading_len += create_leading_static(hdc, opt->title, &lead_static, y,
257 id+ID_STATIC_BASE);
258 psane_control_option(activeDS.deviceHandle, id-ID_BASE,
259 SANE_ACTION_GET_VALUE, buffer,NULL);
261 title = buffer;
262 local_len += MultiByteToWideChar(CP_ACP,0,title,-1,NULL,0);
263 local_len *= sizeof(WCHAR);
265 else if (opt->type == SANE_TYPE_BUTTON)
267 class = 0x0080; /* Button */
268 local_len += MultiByteToWideChar(CP_ACP,0,opt->title,-1,NULL,0);
269 local_len *= sizeof(WCHAR);
270 title = opt->title;
272 else if (opt->type == SANE_TYPE_GROUP)
274 class = 0x0080; /* Button */
275 styles |= BS_GROUPBOX;
276 local_len += MultiByteToWideChar(CP_ACP,0,opt->title,-1,NULL,0);
277 local_len *= sizeof(WCHAR);
278 title = opt->title;
281 local_len += sizeof(DLGITEMTEMPLATE);
282 if (title)
283 local_len += 3*sizeof(WORD);
284 else
285 local_len += 4*sizeof(WORD);
287 if (lead_static)
289 padding = leading_len % sizeof(DWORD);
290 rc = HeapReAlloc(GetProcessHeap(),0,lead_static,leading_len+local_len + padding);
291 tpl = (LPDLGITEMTEMPLATEW)((LPBYTE)rc + leading_len + padding);
293 else
294 rc = tpl = HeapAlloc(GetProcessHeap(),0,local_len);
296 tpl->style=styles;
297 tpl->dwExtendedStyle = 0;
298 if (lead_static)
299 tpl->x = lead_static->x + lead_static->cx + 1;
300 else if (opt->type == SANE_TYPE_GROUP)
301 tpl->x = 2;
302 else
303 tpl->x = 4;
304 tpl->y = y;
305 tpl->id = id;
307 if (title)
309 GetTextExtentPoint32A(hdc,title,lstrlenA(title),&size);
310 tpl->cx = size.cx;
311 tpl->cy = size.cy;
313 else
315 if (lead_static)
316 tpl->cy = lead_static->cy;
317 else
318 tpl->cy = 15;
320 if (!ctl_cx)
321 ctl_cx = 15;
323 tpl->cx = ctl_cx;
325 ptr = (LPBYTE)tpl + sizeof(DLGITEMTEMPLATE);
326 *(LPWORD)ptr = 0xffff;
327 ptr += sizeof(WORD);
328 *(LPWORD)ptr = class;
329 ptr += sizeof(WORD);
330 if (title)
332 ptr += MultiByteToWideChar(CP_ACP,0,title,-1,(LPWSTR)ptr,local_len) * sizeof(WCHAR);
334 else
336 *(LPWORD)ptr = 0x0000;
337 ptr += sizeof(WORD);
340 *((LPWORD)ptr) = 0x0000;
341 ptr += sizeof(WORD);
343 if (trail_edit)
345 trail_edit->x = tpl->cx + tpl->x + 2;
346 *cx = trail_edit->x + trail_edit->cx;
348 padding2 = (leading_len + local_len + padding)% sizeof(DWORD);
350 rc = HeapReAlloc(GetProcessHeap(),0,rc,leading_len+local_len + padding
351 +padding2+trail_len);
353 memcpy(((LPBYTE)rc) + leading_len + local_len + padding + padding2,
354 trail_edit,trail_len);
356 else
357 *cx = tpl->cx + tpl->x;
359 *template_out = rc;
360 if (leading_len)
361 *count = 2;
362 else
363 *count = 1;
365 if (trail_edit)
366 *count+=1;
368 return leading_len + local_len + padding + padding2 + trail_len;
372 static LPDLGTEMPLATEW create_options_page(HDC hdc, int *from_index,
373 SANE_Int optcount, BOOL split_tabs)
375 int i;
376 INT y = 2;
377 LPDLGTEMPLATEW tpl = NULL;
378 LPBYTE all_controls = NULL;
379 DWORD control_len = 0;
380 int max_cx = 0;
381 int group_max_cx = 0;
382 LPBYTE ptr;
383 int group_offset = -1;
384 INT control_count = 0;
386 for (i = *from_index; i < optcount; i++)
388 LPDLGITEMTEMPLATEW item_tpl = NULL;
389 const SANE_Option_Descriptor *opt;
390 int len;
391 int padding = 0;
392 int x;
393 int count;
394 int hold_for_group = 0;
396 opt = psane_get_option_descriptor(activeDS.deviceHandle, i);
397 if (!opt)
398 continue;
399 if (opt->type == SANE_TYPE_GROUP && split_tabs)
401 if (control_len > 0)
403 *from_index = i - 1;
404 goto exit;
406 else
408 *from_index = i;
409 return NULL;
412 if (!SANE_OPTION_IS_ACTIVE (opt->cap))
413 continue;
415 len = create_item(hdc, opt, ID_BASE + i, &item_tpl, y, &x, &count);
417 control_count += count;
419 if (!len)
421 continue;
424 hold_for_group = y;
425 y+= item_tpl->cy + 1;
426 max_cx = max(max_cx, x + 2);
427 group_max_cx = max(group_max_cx, x );
429 padding = len % sizeof(DWORD);
431 if (all_controls)
433 LPBYTE newone;
434 newone = HeapReAlloc(GetProcessHeap(),0,all_controls,
435 control_len + len + padding);
436 all_controls = newone;
437 memcpy(all_controls+control_len,item_tpl,len);
438 memset(all_controls+control_len+len,0xca,padding);
439 HeapFree(GetProcessHeap(),0,item_tpl);
441 else
443 if (!padding)
445 all_controls = (LPBYTE)item_tpl;
447 else
449 all_controls = HeapAlloc(GetProcessHeap(),0,len + padding);
450 memcpy(all_controls,item_tpl,len);
451 memset(all_controls+len,0xcb,padding);
452 HeapFree(GetProcessHeap(),0,item_tpl);
456 if (opt->type == SANE_TYPE_GROUP)
458 if (group_offset == -1)
460 group_offset = control_len;
461 group_max_cx = 0;
463 else
465 LPDLGITEMTEMPLATEW group =
466 (LPDLGITEMTEMPLATEW)(all_controls+group_offset);
468 group->cy = hold_for_group - group->y;
469 group->cx = group_max_cx;
471 group = (LPDLGITEMTEMPLATEW)(all_controls+control_len);
472 group->y += 2;
473 y+=2;
474 group_max_cx = 0;
475 group_offset = control_len;
479 control_len += len + padding;
482 if ( group_offset && !split_tabs )
484 LPDLGITEMTEMPLATEW group =
485 (LPDLGITEMTEMPLATEW)(all_controls+group_offset);
486 group->cy = y - group->y;
487 group->cx = group_max_cx;
488 y+=2;
491 *from_index = i-1;
492 exit:
494 tpl = HeapAlloc(GetProcessHeap(),0,sizeof(DLGTEMPLATE) + 3*sizeof(WORD) +
495 control_len);
497 tpl->style = WS_VISIBLE | WS_OVERLAPPEDWINDOW;
498 tpl->dwExtendedStyle = 0;
499 tpl->cdit = control_count;
500 tpl->x = 0;
501 tpl->y = 0;
502 tpl->cx = max_cx + 10;
503 tpl->cy = y + 10;
504 ptr = (LPBYTE)tpl + sizeof(DLGTEMPLATE);
505 *(LPWORD)ptr = 0x0000;
506 ptr+=sizeof(WORD);
507 *(LPWORD)ptr = 0x0000;
508 ptr+=sizeof(WORD);
509 *(LPWORD)ptr = 0x0000;
510 ptr+=sizeof(WORD);
511 memcpy(ptr,all_controls,control_len);
513 HeapFree(GetProcessHeap(),0,all_controls);
515 return tpl;
518 BOOL DoScannerUI(void)
520 HDC hdc;
521 PROPSHEETPAGEW psp[10];
522 int page_count= 0;
523 PROPSHEETHEADERW psh;
524 int index = 1;
525 SANE_Status rc;
526 SANE_Int optcount;
527 UINT psrc;
528 LPWSTR szCaption;
529 DWORD len;
531 hdc = GetDC(0);
533 memset(&psp,0,sizeof(psp));
534 rc = psane_control_option(activeDS.deviceHandle, 0, SANE_ACTION_GET_VALUE,
535 &optcount, NULL);
536 if (rc != SANE_STATUS_GOOD)
538 ERR("Unable to read number of options\n");
539 return FALSE;
542 while (index < optcount)
544 const SANE_Option_Descriptor *opt;
545 psp[page_count].u.pResource = create_options_page(hdc, &index,
546 optcount, TRUE);
547 opt = psane_get_option_descriptor(activeDS.deviceHandle, index);
549 if (opt->type == SANE_TYPE_GROUP)
551 LPWSTR title = NULL;
552 INT len;
554 len = MultiByteToWideChar(CP_ACP,0,opt->title,-1,NULL,0);
555 title = HeapAlloc(GetProcessHeap(),0,len * sizeof(WCHAR));
556 MultiByteToWideChar(CP_ACP,0,opt->title,-1,title,len);
558 psp[page_count].pszTitle = title;
561 if (psp[page_count].u.pResource)
563 psp[page_count].dwSize = sizeof(PROPSHEETPAGEW);
564 psp[page_count].dwFlags = PSP_DLGINDIRECT | PSP_USETITLE;
565 psp[page_count].hInstance = SANE_instance;
566 psp[page_count].pfnDlgProc = DialogProc;
567 psp[page_count].lParam = (LPARAM)&activeDS;
568 page_count ++;
571 index ++;
574 len = lstrlenA(activeDS.identity.Manufacturer)
575 + lstrlenA(activeDS.identity.ProductName) + 2;
576 szCaption = HeapAlloc(GetProcessHeap(),0,len *sizeof(WCHAR));
577 MultiByteToWideChar(CP_ACP,0,activeDS.identity.Manufacturer,-1,
578 szCaption,len);
579 szCaption[lstrlenA(activeDS.identity.Manufacturer)] = ' ';
580 MultiByteToWideChar(CP_ACP,0,activeDS.identity.ProductName,-1,
581 &szCaption[lstrlenA(activeDS.identity.Manufacturer)+1],len);
582 psh.dwSize = sizeof(PROPSHEETHEADERW);
583 psh.dwFlags = PSH_PROPSHEETPAGE|PSH_PROPTITLE|PSH_USECALLBACK;
584 psh.hwndParent = activeDS.hwndOwner;
585 psh.hInstance = SANE_instance;
586 psh.u.pszIcon = 0;
587 psh.pszCaption = szCaption;
588 psh.nPages = page_count;
589 psh.u2.nStartPage = 0;
590 psh.u3.ppsp = (LPCPROPSHEETPAGEW) &psp;
591 psh.pfnCallback = PropSheetProc;
593 psrc = PropertySheetW(&psh);
595 for(index = 0; index < page_count; index ++)
597 HeapFree(GetProcessHeap(),0,(LPBYTE)psp[index].u.pResource);
598 HeapFree(GetProcessHeap(),0,(LPBYTE)psp[index].pszTitle);
600 HeapFree(GetProcessHeap(),0,szCaption);
602 if (psrc == IDOK)
603 return TRUE;
604 else
605 return FALSE;
608 static void UpdateRelevantEdit(HWND hwnd, const SANE_Option_Descriptor *opt,
609 int index, int position)
611 WCHAR buffer[244];
612 HWND edit_w;
613 int len;
615 if (opt->type == SANE_TYPE_INT)
617 static const WCHAR formatW[] = {'%','i',0};
618 INT si;
620 if (opt->constraint.range->quant)
621 si = position * opt->constraint.range->quant;
622 else
623 si = position;
625 len = wsprintfW( buffer, formatW, si );
627 else if (opt->type == SANE_TYPE_FIXED)
629 static const WCHAR formatW[] = {'%','f',0};
630 double s_quant, dd;
632 s_quant = SANE_UNFIX(opt->constraint.range->quant);
634 if (s_quant)
635 dd = position * s_quant;
636 else
637 dd = position * 0.01;
639 len = wsprintfW( buffer, formatW, dd );
641 else return;
643 buffer[len++] = ' ';
644 LoadStringW( SANE_instance, opt->unit, buffer + len, sizeof(buffer)/sizeof(WCHAR) - len );
646 edit_w = GetDlgItem(hwnd,index+ID_BASE+ID_EDIT_BASE);
647 if (edit_w) SetWindowTextW(edit_w,buffer);
651 static BOOL UpdateSaneScrollOption(
652 const SANE_Option_Descriptor *opt, int index, DWORD position)
654 SANE_Status rc = SANE_STATUS_GOOD;
655 SANE_Int result = 0;
657 if (opt->type == SANE_TYPE_INT)
659 SANE_Int si;
661 if (opt->constraint.range->quant)
662 si = position * opt->constraint.range->quant;
663 else
664 si = position;
666 rc = psane_control_option (activeDS.deviceHandle,index,
667 SANE_ACTION_SET_VALUE, &si, &result);
670 else if (opt->type == SANE_TYPE_FIXED)
672 double s_quant, dd;
673 SANE_Fixed *sf;
675 s_quant = SANE_UNFIX(opt->constraint.range->quant);
677 if (s_quant)
678 dd = position * s_quant;
679 else
680 dd = position * 0.01;
682 sf = HeapAlloc(GetProcessHeap(),0,opt->size*sizeof(SANE_Word));
684 *sf = SANE_FIX(dd);
686 rc = psane_control_option (activeDS.deviceHandle,index,
687 SANE_ACTION_SET_VALUE, sf, &result);
689 HeapFree(GetProcessHeap(),0,sf);
692 if(rc == SANE_STATUS_GOOD)
694 if (result & SANE_INFO_RELOAD_OPTIONS ||
695 result & SANE_INFO_RELOAD_PARAMS || result & SANE_INFO_INEXACT)
696 return TRUE;
698 return FALSE;
701 static BOOL UpdateSaneBoolOption(int index, BOOL position)
703 SANE_Status rc = SANE_STATUS_GOOD;
704 SANE_Int result = 0;
705 SANE_Bool si;
707 si = position;
709 rc = psane_control_option (activeDS.deviceHandle,index,
710 SANE_ACTION_SET_VALUE, &si, &result);
712 if(rc == SANE_STATUS_GOOD)
714 if (result & SANE_INFO_RELOAD_OPTIONS ||
715 result & SANE_INFO_RELOAD_PARAMS || result & SANE_INFO_INEXACT)
716 return TRUE;
718 return FALSE;
721 static BOOL UpdateSaneStringOption(int index, SANE_String value)
723 SANE_Status rc = SANE_STATUS_GOOD;
724 SANE_Int result = 0;
726 rc = psane_control_option (activeDS.deviceHandle,index,
727 SANE_ACTION_SET_VALUE, value, &result);
729 if(rc == SANE_STATUS_GOOD)
731 if (result & SANE_INFO_RELOAD_OPTIONS ||
732 result & SANE_INFO_RELOAD_PARAMS || result & SANE_INFO_INEXACT)
733 return TRUE;
735 return FALSE;
738 static INT_PTR InitializeDialog(HWND hwnd)
740 SANE_Status rc;
741 SANE_Int optcount;
742 HWND control;
743 int i;
745 rc = psane_control_option(activeDS.deviceHandle, 0, SANE_ACTION_GET_VALUE,
746 &optcount, NULL);
747 if (rc != SANE_STATUS_GOOD)
749 ERR("Unable to read number of options\n");
750 return FALSE;
753 for ( i = 1; i < optcount; i++)
755 const SANE_Option_Descriptor *opt;
757 control = GetDlgItem(hwnd,i+ID_BASE);
759 if (!control)
760 continue;
762 opt = psane_get_option_descriptor(activeDS.deviceHandle, i);
764 TRACE("%i %s %i %i\n",i,opt->title,opt->type,opt->constraint_type);
766 if (!SANE_OPTION_IS_ACTIVE(opt->cap))
767 EnableWindow(control,FALSE);
768 else
769 EnableWindow(control,TRUE);
771 SendMessageA(control,CB_RESETCONTENT,0,0);
772 /* initialize values */
773 if (opt->type == SANE_TYPE_STRING && opt->constraint_type !=
774 SANE_CONSTRAINT_NONE)
776 int j = 0;
777 CHAR buffer[255];
778 while (opt->constraint.string_list[j]!=NULL)
780 SendMessageA(control,CB_ADDSTRING,0,
781 (LPARAM)opt->constraint.string_list[j]);
782 j++;
784 psane_control_option(activeDS.deviceHandle, i, SANE_ACTION_GET_VALUE, buffer,NULL);
785 SendMessageA(control,CB_SELECTSTRING,0,(LPARAM)buffer);
787 else if (opt->type == SANE_TYPE_BOOL)
789 SANE_Bool b;
790 psane_control_option(activeDS.deviceHandle, i,
791 SANE_ACTION_GET_VALUE, &b, NULL);
792 if (b)
793 SendMessageA(control,BM_SETCHECK,BST_CHECKED,0);
796 else if (opt->constraint_type == SANE_CONSTRAINT_RANGE)
798 if (opt->type == SANE_TYPE_INT)
800 SANE_Int si;
801 int min,max;
803 min = (SANE_Int)opt->constraint.range->min /
804 (((SANE_Int)opt->constraint.range->quant)?
805 (SANE_Int)opt->constraint.range->quant:1);
807 max = (SANE_Int)opt->constraint.range->max /
808 (((SANE_Int)opt->constraint.range->quant)
809 ?(SANE_Int)opt->constraint.range->quant:1);
811 SendMessageA(control,SBM_SETRANGE,min,max);
813 psane_control_option(activeDS.deviceHandle, i,
814 SANE_ACTION_GET_VALUE, &si,NULL);
815 if (opt->constraint.range->quant)
816 si = si / opt->constraint.range->quant;
818 SendMessageW(control,SBM_SETPOS, si, TRUE);
819 UpdateRelevantEdit(hwnd, opt, i, si);
821 else if (opt->type == SANE_TYPE_FIXED)
823 SANE_Fixed *sf;
825 double dd;
826 double s_min,s_max,s_quant;
827 INT pos;
828 int min,max;
830 s_min = SANE_UNFIX(opt->constraint.range->min);
831 s_max = SANE_UNFIX(opt->constraint.range->max);
832 s_quant = SANE_UNFIX(opt->constraint.range->quant);
834 if (s_quant)
836 min = (s_min / s_quant);
837 max = (s_max / s_quant);
839 else
841 min = s_min / 0.01;
842 max = s_max / 0.01;
845 SendMessageA(control,SBM_SETRANGE,min,max);
848 sf = HeapAlloc(GetProcessHeap(),0,opt->size*sizeof(SANE_Word));
849 psane_control_option(activeDS.deviceHandle, i,
850 SANE_ACTION_GET_VALUE, sf,NULL);
852 dd = SANE_UNFIX(*sf);
853 HeapFree(GetProcessHeap(),0,sf);
855 if (s_quant)
856 pos = (dd / s_quant);
857 else
858 pos = dd / 0.01;
860 SendMessageW(control, SBM_SETPOS, pos, TRUE);
862 UpdateRelevantEdit(hwnd, opt, i, pos);
867 return TRUE;
870 static INT_PTR ProcessScroll(HWND hwnd, WPARAM wParam, LPARAM lParam)
872 int index;
873 const SANE_Option_Descriptor *opt;
874 WORD scroll;
875 DWORD position;
877 index = GetDlgCtrlID((HWND)lParam)- ID_BASE;
878 if (index < 0)
879 return FALSE;
881 opt = psane_get_option_descriptor(activeDS.deviceHandle, index);
883 if (!opt)
884 return FALSE;
886 scroll = LOWORD(wParam);
888 switch (scroll)
890 case SB_THUMBTRACK:
891 case SB_THUMBPOSITION:
893 SCROLLINFO si;
894 si.cbSize = sizeof(SCROLLINFO);
895 si.fMask = SIF_TRACKPOS;
896 GetScrollInfo((HWND)lParam,SB_CTL, &si);
897 position = si.nTrackPos;
899 break;
900 case SB_LEFT:
901 case SB_LINELEFT:
902 case SB_PAGELEFT:
903 position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
904 position--;
905 break;
906 case SB_RIGHT:
907 case SB_LINERIGHT:
908 case SB_PAGERIGHT:
909 position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
910 position++;
911 break;
912 default:
913 position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
916 SendMessageW((HWND)lParam,SBM_SETPOS, position, TRUE);
917 position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
919 UpdateRelevantEdit(hwnd, opt, index, position);
920 if (UpdateSaneScrollOption(opt, index, position))
921 InitializeDialog(hwnd);
923 return TRUE;
927 static void ButtonClicked(HWND hwnd, INT id, HWND control)
929 int index;
930 const SANE_Option_Descriptor *opt;
932 index = id - ID_BASE;
933 if (index < 0)
934 return;
936 opt = psane_get_option_descriptor(activeDS.deviceHandle, index);
938 if (!opt)
939 return;
941 if (opt->type == SANE_TYPE_BOOL)
943 BOOL r = SendMessageW(control,BM_GETCHECK,0,0)==BST_CHECKED;
944 if (UpdateSaneBoolOption(index, r))
945 InitializeDialog(hwnd);
949 static void ComboChanged(HWND hwnd, INT id, HWND control)
951 int index;
952 int selection;
953 int len;
954 const SANE_Option_Descriptor *opt;
955 SANE_String value;
957 index = id - ID_BASE;
958 if (index < 0)
959 return;
961 opt = psane_get_option_descriptor(activeDS.deviceHandle, index);
963 if (!opt)
964 return;
966 selection = SendMessageW(control,CB_GETCURSEL,0,0);
967 len = SendMessageW(control,CB_GETLBTEXTLEN,selection,0);
969 len++;
970 value = HeapAlloc(GetProcessHeap(),0,len);
971 SendMessageA(control,CB_GETLBTEXT,selection,(LPARAM)value);
973 if (opt->type == SANE_TYPE_STRING)
975 if (UpdateSaneStringOption(index, value))
976 InitializeDialog(hwnd);
981 static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
983 switch (msg)
985 case WM_INITDIALOG:
986 return InitializeDialog(hwndDlg);
987 case WM_HSCROLL:
988 return ProcessScroll(hwndDlg, wParam, lParam);
989 case WM_NOTIFY:
991 LPPSHNOTIFY psn = (LPPSHNOTIFY)lParam;
992 switch (((NMHDR*)lParam)->code)
994 case PSN_APPLY:
995 if (psn->lParam == TRUE)
997 activeDS.currentState = 6;
998 activeDS.pendingEvent.TWMessage = MSG_XFERREADY;
1000 break;
1001 case PSN_QUERYCANCEL:
1002 activeDS.pendingEvent.TWMessage = MSG_CLOSEDSREQ;
1003 break;
1004 case PSN_SETACTIVE:
1005 InitializeDialog(hwndDlg);
1006 break;
1009 case WM_COMMAND:
1011 switch (HIWORD(wParam))
1013 case BN_CLICKED:
1014 ButtonClicked(hwndDlg,LOWORD(wParam),
1015 (HWND)lParam);
1016 break;
1017 case CBN_SELCHANGE:
1018 ComboChanged(hwndDlg,LOWORD(wParam),
1019 (HWND)lParam);
1024 return FALSE;
1027 static int CALLBACK PropSheetProc(HWND hwnd, UINT msg, LPARAM lParam)
1029 if (msg == PSCB_INITIALIZED)
1031 /* rename OK button to Scan */
1032 HWND scan = GetDlgItem(hwnd,IDOK);
1033 SetWindowTextA(scan,"Scan");
1035 return TRUE;
1039 static INT_PTR CALLBACK ScanningProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1041 return FALSE;
1044 HWND ScanningDialogBox(HWND dialog, LONG progress)
1046 if (!dialog)
1047 dialog = CreateDialogW(SANE_instance,
1048 (LPWSTR)MAKEINTRESOURCE(IDD_DIALOG1), NULL, ScanningProc);
1050 if (progress == -1)
1052 EndDialog(dialog,0);
1053 return NULL;
1056 RedrawWindow(dialog,NULL,NULL,
1057 RDW_INTERNALPAINT|RDW_UPDATENOW|RDW_ALLCHILDREN);
1059 return dialog;
1062 #else /* SONAME_LIBSANE */
1064 BOOL DoScannerUI(void)
1066 return FALSE;
1069 #endif /* SONAME_LIBSANE */