Commit 8358c63e authored by Aric Stewart's avatar Aric Stewart Committed by Alexandre Julliard

twain: Add a property sheet UI for scanning.

parent bec4990c
......@@ -3,7 +3,7 @@ TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = twain_32.dll
IMPORTS = user32 gdi32 kernel32 ntdll
IMPORTS = comctl32 user32 gdi32 kernel32 ntdll
EXTRALIBS = @SANELIBS@
EXTRAINCL = @SANEINCL@
......@@ -13,11 +13,15 @@ C_SRCS = \
ds_ctrl.c \
ds_image.c \
dsm_ctrl.c \
twain32_main.c
twain32_main.c \
ui.c
C_SRCS16 = \
twain16_main.c
RC_SRCS = \
rsrc.rc
SPEC_SRCS16 = twain.spec
@MAKE_DLL_RULES@
......
......@@ -647,11 +647,20 @@ TW_UINT16 TWAIN_EnableDSUserInterface (pTW_IDENTITY pOrigin,
{
if (pUserInterface->ShowUI)
{
BOOL rc;
pSource->currentState = 5; /* Transitions to state 5 */
/* FIXME: we should replace xscanimage with our own device UI */
system ("xscanimage");
pSource->currentState = 6;
pSource->pendingEvent.TWMessage = MSG_XFERREADY;
rc = DoScannerUI(pSource);
if (!rc)
{
pSource->pendingEvent.TWMessage = MSG_CLOSEDSREQ;
}
#ifdef HAVE_SANE
else
{
sane_get_parameters (pSource->deviceHandle, &pSource->sane_param);
pSource->sane_param_valid = TRUE;
}
#endif
}
else
{
......
......@@ -223,6 +223,12 @@ TW_UINT16 TWAIN_ImageMemXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
/* Transfer an image from the source to the application */
if (pSource->currentState == 6)
{
/* trigger scanning dialog */
pSource->progressWnd = ScanningDialogBox(NULL,0);
ScanningDialogBox(pSource->progressWnd,0);
status = sane_start (pSource->deviceHandle);
if (status != SANE_STATUS_GOOD)
{
......@@ -295,8 +301,11 @@ TW_UINT16 TWAIN_ImageMemXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
pImageMemXfer->YOffset = 0;
pImageMemXfer->BytesWritten = consumed_len;
ScanningDialogBox(pSource->progressWnd, consumed_len);
if (status == SANE_STATUS_EOF)
{
ScanningDialogBox(pSource->progressWnd, -1);
TRACE("sane_read: %s\n", sane_strstatus (status));
sane_cancel (pSource->deviceHandle);
twRC = TWRC_XFERDONE;
......@@ -305,6 +314,7 @@ TW_UINT16 TWAIN_ImageMemXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
}
else if (status != SANE_STATUS_EOF)
{
ScanningDialogBox(pSource->progressWnd, -1);
WARN("sane_read: %s\n", sane_strstatus (status));
sane_cancel (pSource->deviceHandle);
pSource->twCC = TWCC_OPERATIONERROR;
......
......@@ -304,6 +304,7 @@ TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
if (newSource)
{
newSource->deviceIndex = i;
status = sane_open(device_list[i]->name,&newSource->deviceHandle);
if (status == SANE_STATUS_GOOD)
{
......
/*
* Twain resource definitions
*
* Copyright 2006 CodeWeavers, Aric Stewart
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define IDD_DIALOG1 0x400
#define IDC_STATIC 0x401
/*
* Top level resource file for Twain
*
* Copyright 2006 CodeWeavers, Aric Stewart
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winnls.h"
#include "resource.h"
#include "twain_En.rc"
......@@ -39,6 +39,7 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
DSM_currentState = 2;
DSM_instance = hinstDLL;
break;
case DLL_PROCESS_DETACH:
......
/*
* English resources for Twain
*
* Copyright 2006 CodeWeavers, Aric Stewart
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 186, 46
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE | DS_CENTER | DS_SETFOREGROUND
CAPTION "Scanning"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "SCANNING.... Please Wait",IDC_STATIC,53,19,85,8
END
STRINGTABLE DISCARDABLE
{
0 ""
1 "px"
2 "b"
3 "mm"
4 "dpi"
5 "%"
6 "ns"
}
......@@ -42,11 +42,13 @@ typedef struct tagActiveDS
application */
TW_UINT16 twCC; /* condition code */
HWND hwndOwner; /* window handle of the app */
HWND progressWnd; /* window handle of the scanning window */
#ifdef HAVE_SANE
SANE_Handle deviceHandle; /* device handle */
SANE_Parameters sane_param; /* parameters about the image
transferred */
BOOL sane_param_valid; /* true if valid sane_param*/
INT deviceIndex; /* index of the current device */
#endif
/* Capabiblities */
TW_UINT16 capXferMech; /* ICAP_XFERMECH */
......@@ -58,6 +60,8 @@ TW_UINT16 DSM_twCC; /* current condition code of Source Manager */
TW_HANDLE DSM_parentHWND; /* window handle of the Source's "parent" */
TW_UINT32 DSM_sourceId; /* source id generator */
TW_UINT16 DSM_currentDevice; /* keep track of device during enumeration */
HINSTANCE DSM_instance;
#ifdef HAVE_SANE
const SANE_Device **device_list;/* a list of all sane devices */
#endif
......@@ -244,4 +248,8 @@ TW_UINT16 TWAIN_AudioNativeXferGet
TW_UINT16 TWAIN_ICAPXferMech
(activeDS *pSource, pTW_CAPABILITY pCapability, TW_UINT16 action);
/* UI function */
BOOL DoScannerUI(activeDS *pSource);
HWND ScanningDialogBox(HWND dialog, DWORD progress);
#endif
/*
* TWAIN32 Options UI
*
* Copyright 2006 CodeWeavers, Aric Stewart
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winnls.h"
#include "wingdi.h"
#include "prsht.h"
#include "twain.h"
#include "twain_i.h"
#include "wine/debug.h"
#include "resource.h"
WINE_DEFAULT_DEBUG_CHANNEL(twain);
#ifdef HAVE_SANE
#define ID_BASE 0x100
#define ID_EDIT_BASE 0x1000
#define ID_STATIC_BASE 0x2000
static INT_PTR CALLBACK DialogProc (HWND , UINT , WPARAM , LPARAM );
static INT CALLBACK PropSheetProc(HWND, UINT,LPARAM);
static int create_leading_static(HDC hdc, LPCSTR text,
LPDLGITEMTEMPLATEW* template_out, int y, int id)
{
LPDLGITEMTEMPLATEW tpl = NULL;
INT len;
SIZE size;
LPBYTE ptr;
LONG base;
*template_out = NULL;
if (!text)
return 0;
base = GetDialogBaseUnits();
len = MultiByteToWideChar(CP_ACP,0,text,-1,NULL,0);
len *= sizeof(WCHAR);
len += sizeof(DLGITEMTEMPLATE);
len += 3*sizeof(WORD);
tpl = HeapAlloc(GetProcessHeap(),0,len);
tpl->style=WS_VISIBLE;
tpl->dwExtendedStyle = 0;
tpl->x = 4;
tpl->y = y;
tpl->id = ID_BASE;
GetTextExtentPoint32A(hdc,text,lstrlenA(text),&size);
tpl->cx = MulDiv(size.cx,4,LOWORD(base));
tpl->cy = MulDiv(size.cy,8,HIWORD(base)) * 2;
ptr = (LPBYTE)tpl + sizeof(DLGITEMTEMPLATE);
*(LPWORD)ptr = 0xffff;
ptr += sizeof(WORD);
*(LPWORD)ptr = 0x0082;
ptr += sizeof(WORD);
ptr += MultiByteToWideChar(CP_ACP,0,text,-1,(LPWSTR)ptr,len) * sizeof(WCHAR);
*(LPWORD)ptr = 0x0000;
*template_out = tpl;
return len;
}
static int create_trailing_edit(HDC hdc, LPDLGITEMTEMPLATEW* template_out, int id,
int y, LPCSTR text,BOOL is_int)
{
LPDLGITEMTEMPLATEW tpl = NULL;
INT len;
LPBYTE ptr;
SIZE size;
LONG base;
static const char int_base[] = "0000 xxx";
static const char float_base[] = "0000.0000 xxx";
base = GetDialogBaseUnits();
len = MultiByteToWideChar(CP_ACP,0,text,-1,NULL,0);
len *= sizeof(WCHAR);
len += sizeof(DLGITEMTEMPLATE);
len += 3*sizeof(WORD);
tpl = HeapAlloc(GetProcessHeap(),0,len);
tpl->style=WS_VISIBLE|ES_READONLY|WS_BORDER;
tpl->dwExtendedStyle = 0;
tpl->x = 1;
tpl->y = y;
tpl->id = id;
if (is_int)
GetTextExtentPoint32A(hdc,int_base,lstrlenA(int_base),&size);
else
GetTextExtentPoint32A(hdc,float_base,lstrlenA(float_base),&size);
tpl->cx = MulDiv(size.cx*2,4,LOWORD(base));
tpl->cy = MulDiv(size.cy,8,HIWORD(base)) * 2;
ptr = (LPBYTE)tpl + sizeof(DLGITEMTEMPLATE);
*(LPWORD)ptr = 0xffff;
ptr += sizeof(WORD);
*(LPWORD)ptr = 0x0081;
ptr += sizeof(WORD);
ptr += MultiByteToWideChar(CP_ACP,0,text,-1,(LPWSTR)ptr,len) * sizeof(WCHAR);
*(LPWORD)ptr = 0x0000;
*template_out = tpl;
return len;
}
static int create_item(activeDS *pSource,HDC hdc, const SANE_Option_Descriptor *opt,
INT id, LPDLGITEMTEMPLATEW *template_out, int y, int *cx, int* count)
{
LPDLGITEMTEMPLATEW tpl = NULL,rc = NULL;
WORD class = 0xffff;
DWORD styles = WS_VISIBLE;
LPBYTE ptr = NULL;
LPDLGITEMTEMPLATEW lead_static = NULL;
LPDLGITEMTEMPLATEW trail_edit = NULL;
DWORD leading_len = 0;
DWORD trail_len = 0;
DWORD local_len = 0;
LPCSTR title = NULL;
CHAR buffer[255];
int padding = 0;
int padding2 = 0;
int base_x = 0;
LONG base;
int ctl_cx = 0;
SIZE size;
GetTextExtentPoint32A(hdc,"X",1,&size);
base = GetDialogBaseUnits();
base_x = MulDiv(size.cx,4,LOWORD(base));
if (opt->type == SANE_TYPE_BOOL)
{
class = 0x0080; /* Button */
styles |= BS_AUTOCHECKBOX;
local_len += MultiByteToWideChar(CP_ACP,0,opt->title,-1,NULL,0);
local_len *= sizeof(WCHAR);
title = opt->title;
}
else if (opt->type == SANE_TYPE_INT)
{
SANE_Int i;
sane_control_option(pSource->deviceHandle, id-ID_BASE,
SANE_ACTION_GET_VALUE, &i,NULL);
sprintf(buffer,"%i",i);
if (opt->constraint_type == SANE_CONSTRAINT_NONE)
{
class = 0x0081; /* Edit*/
styles |= ES_NUMBER;
title = buffer;
local_len += MultiByteToWideChar(CP_ACP,0,title,-1,NULL,0);
local_len *= sizeof(WCHAR);
}
else if (opt->constraint_type == SANE_CONSTRAINT_RANGE)
{
class = 0x0084; /* scroll */
ctl_cx = 10 * base_x;
trail_len += create_trailing_edit(hdc, &trail_edit, id +
ID_EDIT_BASE, y,buffer,TRUE);
}
else
{
class= 0x0085; /* Combo */
ctl_cx = 10 * base_x;
styles |= CBS_DROPDOWNLIST;
}
leading_len += create_leading_static(hdc, opt->title, &lead_static, y,
id+ID_STATIC_BASE);
}
else if (opt->type == SANE_TYPE_FIXED)
{
SANE_Fixed *i;
double dd;
i = HeapAlloc(GetProcessHeap(),0,opt->size*sizeof(SANE_Word));
sane_control_option(pSource->deviceHandle, id-ID_BASE,
SANE_ACTION_GET_VALUE, i, NULL);
dd = SANE_UNFIX(*i);
sprintf(buffer,"%f",dd);
HeapFree(GetProcessHeap(),0,i);
if (opt->constraint_type == SANE_CONSTRAINT_NONE)
{
class = 0x0081; /* Edit */
title = buffer;
local_len += MultiByteToWideChar(CP_ACP,0,title,-1,NULL,0);
local_len *= sizeof(WCHAR);
}
else if (opt->constraint_type == SANE_CONSTRAINT_RANGE)
{
class= 0x0084; /* scroll */
ctl_cx = 10 * base_x;
trail_len += create_trailing_edit(hdc, &trail_edit, id +
ID_EDIT_BASE, y,buffer,FALSE);
}
else
{
class= 0x0085; /* Combo */
ctl_cx = 10 * base_x;
styles |= CBS_DROPDOWNLIST;
}
leading_len += create_leading_static(hdc, opt->title, &lead_static, y,
id+ID_STATIC_BASE);
}
else if (opt->type == SANE_TYPE_STRING)
{
if (opt->constraint_type == SANE_CONSTRAINT_NONE)
{
class = 0x0081; /* Edit*/
}
else
{
class= 0x0085; /* Combo */
ctl_cx = opt->size * base_x;
styles |= CBS_DROPDOWNLIST;
}
leading_len += create_leading_static(hdc, opt->title, &lead_static, y,
id+ID_STATIC_BASE);
sane_control_option(pSource->deviceHandle, id-ID_BASE,
SANE_ACTION_GET_VALUE, buffer,NULL);
title = buffer;
local_len += MultiByteToWideChar(CP_ACP,0,title,-1,NULL,0);
local_len *= sizeof(WCHAR);
}
else if (opt->type == SANE_TYPE_BUTTON)
{
class = 0x0080; /* Button */
local_len += MultiByteToWideChar(CP_ACP,0,opt->title,-1,NULL,0);
local_len *= sizeof(WCHAR);
title = opt->title;
}
else if (opt->type == SANE_TYPE_GROUP)
{
class = 0x0080; /* Button */
styles |= BS_GROUPBOX;
local_len += MultiByteToWideChar(CP_ACP,0,opt->title,-1,NULL,0);
local_len *= sizeof(WCHAR);
title = opt->title;
}
local_len += sizeof(DLGITEMTEMPLATE);
if (title)
local_len += 3*sizeof(WORD);
else
local_len += 4*sizeof(WORD);
if (lead_static)
{
padding = leading_len % sizeof(DWORD);
rc = HeapReAlloc(GetProcessHeap(),0,lead_static,leading_len+local_len + padding);
tpl = (LPDLGITEMTEMPLATEW)((LPBYTE)rc + leading_len + padding);
}
else
rc = tpl = HeapAlloc(GetProcessHeap(),0,local_len);
tpl->style=styles;
tpl->dwExtendedStyle = 0;
if (lead_static)
tpl->x = lead_static->x + lead_static->cx + 1;
else if (opt->type == SANE_TYPE_GROUP)
tpl->x = 2;
else
tpl->x = 4;
tpl->y = y;
tpl->id = id;
if (title)
{
GetTextExtentPoint32A(hdc,title,lstrlenA(title),&size);
tpl->cx = size.cx;
tpl->cy = size.cy;
}
else
{
if (lead_static)
tpl->cy = lead_static->cy;
else
tpl->cy = 15;
if (!ctl_cx)
ctl_cx = 15;
tpl->cx = ctl_cx;
}
ptr = (LPBYTE)tpl + sizeof(DLGITEMTEMPLATE);
*(LPWORD)ptr = 0xffff;
ptr += sizeof(WORD);
*(LPWORD)ptr = class;
ptr += sizeof(WORD);
if (title)
{
ptr += MultiByteToWideChar(CP_ACP,0,title,-1,(LPWSTR)ptr,local_len) * sizeof(WCHAR);
}
else
{
*(LPWORD)ptr = 0x0000;
ptr += sizeof(WORD);
}
*((LPWORD)ptr) = 0x0000;
ptr += sizeof(WORD);
if (trail_edit)
{
trail_edit->x = tpl->cx + tpl->x + 2;
*cx = trail_edit->x + trail_edit->cx;
padding2 = (leading_len + local_len + padding)% sizeof(DWORD);
rc = HeapReAlloc(GetProcessHeap(),0,rc,leading_len+local_len + padding
+padding2+trail_len);
memcpy(((LPBYTE)rc) + leading_len + local_len + padding + padding2,
trail_edit,trail_len);
}
else
*cx = tpl->cx + tpl->x;
*template_out = rc;
if (leading_len)
*count = 2;
else
*count = 1;
if (trail_edit)
*count+=1;
return leading_len + local_len + padding + padding2 + trail_len;
}
static LPDLGTEMPLATEW create_options_page(HDC hdc, activeDS *pSource, int *from_index,
BOOL split_tabs)
{
SANE_Status rc;
SANE_Int optcount;
int i;
INT y = 2;
LPDLGTEMPLATEW tpl = NULL;
LPBYTE all_controls = NULL;
DWORD control_len = 0;
int max_cx = 0;
int group_max_cx = 0;
LPBYTE ptr;
int group_offset = -1;
INT control_count = 0;
rc = sane_control_option(pSource->deviceHandle, 0, SANE_ACTION_GET_VALUE,
&optcount, NULL);
if (rc != SANE_STATUS_GOOD)
{
ERR("Unable to read number of options\n");
return NULL;
}
for (i = *from_index; i < optcount; i++)
{
LPDLGITEMTEMPLATEW item_tpl = NULL;
const SANE_Option_Descriptor *opt;
int len;
int padding = 0;
int x;
int count;
int hold_for_group = 0;
opt = sane_get_option_descriptor(pSource->deviceHandle, i);
if (opt->type == SANE_TYPE_GROUP && split_tabs)
{
if (control_len > 0)
{
*from_index = i - 1;
goto exit;
}
else
{
*from_index = i;
return NULL;
}
}
len = create_item(pSource, hdc, opt, ID_BASE + i, &item_tpl, y, &x,
&count);
control_count += count;
if (!len)
{
continue;
}
hold_for_group = y;
y+= item_tpl->cy + 1;
max_cx = max(max_cx, x + 2);
group_max_cx = max(group_max_cx, x );
padding = len % sizeof(DWORD);
if (all_controls)
{
LPBYTE newone;
newone = HeapReAlloc(GetProcessHeap(),0,all_controls,
control_len + len + padding);
all_controls = newone;
memcpy(all_controls+control_len,item_tpl,len);
memset(all_controls+control_len+len,0xca,padding);
HeapFree(GetProcessHeap(),0,item_tpl);
}
else
{
if (!padding)
{
all_controls = (LPBYTE)item_tpl;
}
else
{
all_controls = HeapAlloc(GetProcessHeap(),0,len + padding);
memcpy(all_controls,item_tpl,len);
memset(all_controls+len,0xcb,padding);
HeapFree(GetProcessHeap(),0,item_tpl);
}
}
if (opt->type == SANE_TYPE_GROUP)
{
if (group_offset == -1)
{
group_offset = control_len;
group_max_cx = 0;
}
else
{
LPDLGITEMTEMPLATEW group =
(LPDLGITEMTEMPLATEW)(all_controls+group_offset);
group->cy = hold_for_group - group->y;
group->cx = group_max_cx;
group = (LPDLGITEMTEMPLATEW)(all_controls+control_len);
group->y += 2;
y+=2;
group_max_cx = 0;
group_offset = control_len;
}
}
control_len += len + padding;
}
if ( group_offset && !split_tabs )
{
LPDLGITEMTEMPLATEW group =
(LPDLGITEMTEMPLATEW)(all_controls+group_offset);
group->cy = y - group->y;
group->cx = group_max_cx;
y+=2;
}
*from_index = i-1;
exit:
tpl = HeapAlloc(GetProcessHeap(),0,sizeof(DLGTEMPLATE) + 3*sizeof(WORD) +
control_len);
tpl->style = WS_VISIBLE | WS_OVERLAPPEDWINDOW;
tpl->dwExtendedStyle = 0;
tpl->cdit = control_count;
tpl->x = 0;
tpl->y = 0;
tpl->cx = max_cx + 10;
tpl->cy = y + 10;
ptr = (LPBYTE)tpl + sizeof(DLGTEMPLATE);
*(LPWORD)ptr = 0x0000;
ptr+=sizeof(WORD);
*(LPWORD)ptr = 0x0000;
ptr+=sizeof(WORD);
*(LPWORD)ptr = 0x0000;
ptr+=sizeof(WORD);
memcpy(ptr,all_controls,control_len);
HeapFree(GetProcessHeap(),0,all_controls);
return tpl;
}
BOOL DoScannerUI(activeDS *pSource)
{
HDC hdc;
PROPSHEETPAGEW psp[10];
int page_count= 0;
PROPSHEETHEADERW psh;
int index = 1;
SANE_Status rc;
SANE_Int optcount;
UINT psrc;
LPWSTR szCaption;
DWORD len;
hdc = GetDC(0);
memset(&psp,0,sizeof(psp));
rc = sane_control_option(pSource->deviceHandle, 0, SANE_ACTION_GET_VALUE,
&optcount, NULL);
while (index < optcount)
{
const SANE_Option_Descriptor *opt;
psp[page_count].u.pResource = create_options_page(hdc, pSource, &index,
TRUE);
opt = sane_get_option_descriptor(pSource->deviceHandle, index);
if (opt->type == SANE_TYPE_GROUP)
{
LPWSTR title = NULL;
INT len;
len = MultiByteToWideChar(CP_ACP,0,opt->title,-1,NULL,0);
title = HeapAlloc(GetProcessHeap(),0,len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP,0,opt->title,-1,title,len);
psp[page_count].pszTitle = title;
}
if (psp[page_count].u.pResource)
{
psp[page_count].dwSize = sizeof(PROPSHEETPAGEW);
psp[page_count].dwFlags = PSP_DLGINDIRECT | PSP_USETITLE;
psp[page_count].hInstance = DSM_instance;
psp[page_count].pfnDlgProc = DialogProc;
psp[page_count].lParam = (LPARAM)pSource;
page_count ++;
}
index ++;
}
len = lstrlenA(device_list[pSource->deviceIndex]->vendor)
+ lstrlenA(device_list[pSource->deviceIndex]->model) + 2;
szCaption = HeapAlloc(GetProcessHeap(),0,len *sizeof(WCHAR));
MultiByteToWideChar(CP_ACP,0,device_list[pSource->deviceIndex]->vendor,-1,
szCaption,len);
szCaption[lstrlenA(device_list[pSource->deviceIndex]->vendor)] = ' ';
MultiByteToWideChar(CP_ACP,0,device_list[pSource->deviceIndex]->model,-1,
&szCaption[lstrlenA(device_list[pSource->deviceIndex]->vendor)+1],len);
psh.dwSize = sizeof(PROPSHEETHEADERW);
psh.dwFlags = PSH_PROPSHEETPAGE|PSH_PROPTITLE|PSH_USECALLBACK;
psh.hwndParent = DSM_parentHWND;
psh.hInstance = DSM_instance;
psh.u.pszIcon = 0;
psh.pszCaption = szCaption;
psh.nPages = page_count;
psh.u2.nStartPage = 0;
psh.u3.ppsp = (LPCPROPSHEETPAGEW) &psp;
psh.pfnCallback = PropSheetProc;
psrc = PropertySheetW(&psh);
for(index = 0; index < page_count; index ++)
{
HeapFree(GetProcessHeap(),0,(LPBYTE)psp[index].u.pResource);
HeapFree(GetProcessHeap(),0,(LPBYTE)psp[index].pszTitle);
}
if (psrc == IDOK)
return TRUE;
else
return FALSE;
}
static void UpdateRelevantEdit(HWND hwnd, const SANE_Option_Descriptor *opt,
int index, int position)
{
CHAR buffer[244];
HWND edit_w;
CHAR unit[20];
LoadStringA(DSM_instance, opt->unit, unit,20);
if (opt->type == SANE_TYPE_INT)
{
INT si;
if (opt->constraint.range->quant)
si = position * opt->constraint.range->quant;
else
si = position;
sprintf(buffer,"%i %s",si,unit);
}
else if (opt->type == SANE_TYPE_FIXED)
{
double s_quant, dd;
s_quant = SANE_UNFIX(opt->constraint.range->quant);
if (s_quant)
dd = position * s_quant;
else
dd = position * 0.01;
sprintf(buffer,"%f %s",dd,unit);
}
else
buffer[0] = 0;
edit_w = GetDlgItem(hwnd,index+ID_BASE+ID_EDIT_BASE);
if (edit_w && buffer[0])
SetWindowTextA(edit_w,buffer);
}
static BOOL UpdateSaneScrollOption(activeDS *pSource,
const SANE_Option_Descriptor *opt, int index, DWORD position)
{
SANE_Status rc = SANE_STATUS_GOOD;
SANE_Int result = 0;
if (opt->type == SANE_TYPE_INT)
{
SANE_Int si;
if (opt->constraint.range->quant)
si = position * opt->constraint.range->quant;
else
si = position;
rc = sane_control_option (pSource->deviceHandle,index,
SANE_ACTION_SET_VALUE, &si, &result);
}
else if (opt->type == SANE_TYPE_FIXED)
{
double s_quant, dd;
SANE_Fixed *sf;
s_quant = SANE_UNFIX(opt->constraint.range->quant);
if (s_quant)
dd = position * s_quant;
else
dd = position * 0.01;
sf = HeapAlloc(GetProcessHeap(),0,opt->size*sizeof(SANE_Word));
*sf = SANE_FIX(dd);
rc = sane_control_option (pSource->deviceHandle,index,
SANE_ACTION_SET_VALUE, sf, &result);
HeapFree(GetProcessHeap(),0,sf);
}
if(rc == SANE_STATUS_GOOD)
{
if (result & SANE_INFO_RELOAD_OPTIONS ||
result & SANE_INFO_RELOAD_PARAMS || result & SANE_INFO_INEXACT)
return TRUE;
}
return FALSE;
}
static BOOL UpdateSaneBoolOption(activeDS *pSource, int index, BOOL position)
{
SANE_Status rc = SANE_STATUS_GOOD;
SANE_Int result = 0;
SANE_Bool si;
si = position;
rc = sane_control_option (pSource->deviceHandle,index,
SANE_ACTION_SET_VALUE, &si, &result);
if(rc == SANE_STATUS_GOOD)
{
if (result & SANE_INFO_RELOAD_OPTIONS ||
result & SANE_INFO_RELOAD_PARAMS || result & SANE_INFO_INEXACT)
return TRUE;
}
return FALSE;
}
static BOOL UpdateSaneStringOption(activeDS *pSource, int index,
SANE_String value)
{
SANE_Status rc = SANE_STATUS_GOOD;
SANE_Int result = 0;
rc = sane_control_option (pSource->deviceHandle,index,
SANE_ACTION_SET_VALUE, value, &result);
if(rc == SANE_STATUS_GOOD)
{
if (result & SANE_INFO_RELOAD_OPTIONS ||
result & SANE_INFO_RELOAD_PARAMS || result & SANE_INFO_INEXACT)
return TRUE;
}
return FALSE;
}
static INT_PTR InitializeDialog(HWND hwnd, activeDS *pSource)
{
SANE_Status rc;
SANE_Int optcount;
HWND control;
int i;
rc = sane_control_option(pSource->deviceHandle, 0, SANE_ACTION_GET_VALUE,
&optcount, NULL);
for ( i = 1; i < optcount; i++)
{
const SANE_Option_Descriptor *opt;
control = GetDlgItem(hwnd,i+ID_BASE);
if (!control)
continue;
opt = sane_get_option_descriptor(pSource->deviceHandle, i);
TRACE("%i %s %i %i\n",i,opt->title,opt->type,opt->constraint_type);
if (!SANE_OPTION_IS_ACTIVE(opt->cap))
EnableWindow(control,FALSE);
else
EnableWindow(control,TRUE);
SendMessageA(control,CB_RESETCONTENT,0,0);
/* initialize values */
if (opt->type == SANE_TYPE_STRING && opt->constraint_type !=
SANE_CONSTRAINT_NONE)
{
int j = 0;
CHAR buffer[255];
while (opt->constraint.string_list[j]!=NULL)
{
SendMessageA(control,CB_ADDSTRING,0,
(LPARAM)opt->constraint.string_list[j]);
j++;
}
sane_control_option(pSource->deviceHandle, i, SANE_ACTION_GET_VALUE, buffer,NULL);
SendMessageA(control,CB_SELECTSTRING,0,(LPARAM)buffer);
}
else if (opt->type == SANE_TYPE_BOOL)
{
SANE_Bool b;
sane_control_option(pSource->deviceHandle, i,
SANE_ACTION_GET_VALUE, &b, NULL);
if (b)
SendMessageA(control,BM_SETCHECK,BST_CHECKED,0);
}
else if (opt->constraint_type == SANE_CONSTRAINT_RANGE)
{
if (opt->type == SANE_TYPE_INT)
{
SANE_Int si;
int min,max;
min = (SANE_Int)opt->constraint.range->min /
(((SANE_Int)opt->constraint.range->quant)?
(SANE_Int)opt->constraint.range->quant:1);
max = (SANE_Int)opt->constraint.range->max /
(((SANE_Int)opt->constraint.range->quant)
?(SANE_Int)opt->constraint.range->quant:1);
SendMessageA(control,SBM_SETRANGE,min,max);
sane_control_option(pSource->deviceHandle, i,
SANE_ACTION_GET_VALUE, &si,NULL);
if (opt->constraint.range->quant)
si = si / opt->constraint.range->quant;
SendMessageW(control,SBM_SETPOS, si, TRUE);
UpdateRelevantEdit(hwnd, opt, i, si);
}
else if (opt->type == SANE_TYPE_FIXED)
{
SANE_Fixed *sf;
double dd;
double s_min,s_max,s_quant;
INT pos;
int min,max;
s_min = SANE_UNFIX(opt->constraint.range->min);
s_max = SANE_UNFIX(opt->constraint.range->max);
s_quant = SANE_UNFIX(opt->constraint.range->quant);
if (s_quant)
{
min = (s_min / s_quant);
max = (s_max / s_quant);
}
else
{
min = s_min / 0.01;
max = s_max / 0.01;
}
SendMessageA(control,SBM_SETRANGE,min,max);
sf = HeapAlloc(GetProcessHeap(),0,opt->size*sizeof(SANE_Word));
sane_control_option(pSource->deviceHandle, i,
SANE_ACTION_GET_VALUE, sf,NULL);
dd = SANE_UNFIX(*sf);
HeapFree(GetProcessHeap(),0,sf);
if (s_quant)
pos = (dd / s_quant);
else
pos = dd / 0.01;
SendMessageW(control, SBM_SETPOS, pos, TRUE);
UpdateRelevantEdit(hwnd, opt, i, pos);
}
}
}
return TRUE;
}
static INT_PTR ProcessScroll(HWND hwnd, activeDS *pSource, WPARAM wParam,
LPARAM lParam)
{
int index;
const SANE_Option_Descriptor *opt;
WORD scroll;
DWORD position;
index = GetDlgCtrlID((HWND)lParam)- ID_BASE;
if (index < 0)
return FALSE;
opt = sane_get_option_descriptor(pSource->deviceHandle, index);
if (!opt)
return FALSE;
scroll = LOWORD(wParam);
switch (scroll)
{
case SB_THUMBTRACK:
case SB_THUMBPOSITION:
{
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_TRACKPOS;
GetScrollInfo((HWND)lParam,SB_CTL, &si);
position = si.nTrackPos;
}
break;
case SB_LEFT:
case SB_LINELEFT:
case SB_PAGELEFT:
position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
position--;
break;
case SB_RIGHT:
case SB_LINERIGHT:
case SB_PAGERIGHT:
position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
position++;
break;
default:
position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
}
SendMessageW((HWND)lParam,SBM_SETPOS, position, TRUE);
position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
UpdateRelevantEdit(hwnd, opt, index, position);
if (UpdateSaneScrollOption(pSource, opt, index, position))
InitializeDialog(hwnd,pSource);
return TRUE;
}
static void ButtonClicked(HWND hwnd, activeDS* pSource,INT id, HWND control)
{
int index;
const SANE_Option_Descriptor *opt;
index = id - ID_BASE;
if (index < 0)
return;
opt = sane_get_option_descriptor(pSource->deviceHandle, index);
if (!opt)
return;
if (opt->type == SANE_TYPE_BOOL)
{
BOOL r = SendMessageW(control,BM_GETCHECK,0,0)==BST_CHECKED;
if (UpdateSaneBoolOption(pSource, index, r))
InitializeDialog(hwnd,pSource);
}
}
static void ComboChanged(HWND hwnd, activeDS* pSource,INT id, HWND control)
{
int index;
int selection;
int len;
const SANE_Option_Descriptor *opt;
SANE_String value;
index = id - ID_BASE;
if (index < 0)
return;
opt = sane_get_option_descriptor(pSource->deviceHandle, index);
if (!opt)
return;
selection = SendMessageW(control,CB_GETCURSEL,0,0);
len = SendMessageW(control,CB_GETLBTEXTLEN,selection,0);
len++;
value = HeapAlloc(GetProcessHeap(),0,len);
SendMessageA(control,CB_GETLBTEXT,selection,(LPARAM)value);
if (opt->type == SANE_TYPE_STRING)
{
if (UpdateSaneStringOption(pSource, index, value))
InitializeDialog(hwnd,pSource);
}
}
static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
static activeDS *pSource = NULL;
switch (msg)
{
case WM_INITDIALOG:
pSource = (activeDS*)((LPPROPSHEETPAGEW)lParam)->lParam;
return InitializeDialog(hwndDlg, pSource);
case WM_HSCROLL:
return ProcessScroll(hwndDlg, pSource, wParam, lParam);
break;
case WM_NOTIFY:
{
LPPSHNOTIFY psn = (LPPSHNOTIFY)lParam;
switch (((NMHDR*)lParam)->code)
{
case PSN_APPLY:
if (psn->lParam == TRUE)
{
pSource->currentState = 6;
pSource->pendingEvent.TWMessage = MSG_XFERREADY;
}
break;
case PSN_QUERYCANCEL:
pSource->pendingEvent.TWMessage = MSG_CLOSEDSREQ;
break;
case PSN_SETACTIVE:
InitializeDialog(hwndDlg, pSource);
break;
}
}
case WM_COMMAND:
{
switch (HIWORD(wParam))
{
case BN_CLICKED:
ButtonClicked(hwndDlg, pSource,LOWORD(wParam),
(HWND)lParam);
break;
case CBN_SELCHANGE:
ComboChanged(hwndDlg, pSource,LOWORD(wParam),
(HWND)lParam);
}
}
}
return FALSE;
}
static int CALLBACK PropSheetProc(HWND hwnd, UINT msg, LPARAM lParam)
{
if (msg == PSCB_INITIALIZED)
{
/* rename OK button to Scan */
HWND scan = GetDlgItem(hwnd,IDOK);
SetWindowTextA(scan,"Scan");
}
return TRUE;
}
static INT_PTR CALLBACK ScanningProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
return FALSE;
}
HWND ScanningDialogBox(HWND dialog, DWORD progress)
{
if (!dialog)
dialog = CreateDialogW(DSM_instance,
(LPWSTR)MAKEINTRESOURCE(IDD_DIALOG1), NULL, ScanningProc);
if (progress == -1)
{
EndDialog(dialog,0);
return NULL;
}
RedrawWindow(dialog,NULL,NULL,
RDW_INTERNALPAINT|RDW_UPDATENOW|RDW_ALLCHILDREN);
return dialog;
}
#else /* HAVE_SANE */
BOOL DoScannerUI(activeDS *pSource)
{
return FALSE;
}
#endif /* HAVE_SANE */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment