Module: win32-duim Synopsis: Win32 pixmap implementation Author: David Gray, Scott McKay, Andy Armstrong Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND /// Win32 pixmaps define sealed class (, ) sealed constant slot image-width :: , required-init-keyword: width:; sealed constant slot image-height :: , required-init-keyword: height:; sealed slot %medium :: , required-init-keyword: medium:; sealed slot %hDC :: = $null-hDC; sealed slot %hbitmap :: = $null-bitmap; end class ; define sealed domain make (singleton()); define sealed domain initialize (); define sealed method do-make-pixmap (_port :: , medium :: , width :: , height :: ) => (pixmap :: ) make(, medium: medium, width: width, height: height) end method do-make-pixmap; define sealed method initialize (pixmap :: , #key width, height, medium) => () next-method(); let hDC :: = get-DC(medium); let bitmap-hDC :: = check-result("CreateCompatibleDC", CreateCompatibleDC(hDC)); let hbitmap :: = check-result("CreateCompatibleBitmap", CreateCompatibleBitmap(hDC, width, height)); SelectObject(bitmap-hDC, hbitmap); pixmap.%hDC := bitmap-hDC; pixmap.%hbitmap := hbitmap end method initialize; define sealed method destroy-pixmap (pixmap :: ) => () unless (pixmap.%hDC = $null-hDC) DeleteDC(pixmap.%hDC); pixmap.%hDC := $null-hDC end; unless (pixmap.%hbitmap = $null-bitmap) DeleteObject(pixmap.%hbitmap); pixmap.%hbitmap := $null-bitmap end; #f end method destroy-pixmap; define sealed method port (pixmap :: ) => (port :: ) port(pixmap.%medium) end method port; define sealed method pixmap-drawable (pixmap :: ) => (drawable) pixmap end method pixmap-drawable; define sealed inline method get-DC (pixmap :: ) => (hDC :: ) pixmap.%hDC end method get-DC; define sealed method draw-image (medium :: , pixmap :: , x, y) => (record) do-copy-area(pixmap, 0, 0, image-width(pixmap), image-height(pixmap), medium, x, y); #f end method draw-image; define sealed method draw-pixmap (medium :: , pixmap :: , x, y, #key function = $boole-1) => (record) do-copy-area(pixmap, 0, 0, image-width(pixmap), image-height(pixmap), medium, x, y, function: function); #f end method draw-pixmap; /// Win32 pixmap mediums define sealed class (, ) end class ; define sealed domain make (singleton()); define sealed domain initialize (); define sealed method make-pixmap-medium (_port :: , sheet :: , #key width, height) => (medium :: ) with-sheet-medium (medium = sheet) let pixmap = do-make-pixmap(_port, medium, width, height); let medium = make(, port: _port, sheet: sheet, pixmap: pixmap); medium-drawable(medium) := pixmap; medium end end method make-pixmap-medium; /// Win32 pixmap sheets (and mirrors) define sealed method map-mirror (_port :: , sheet :: , mirror :: ) => () #f end method map-mirror; define sealed method unmap-mirror (_port :: , sheet :: , mirror :: ) => () #f end method unmap-mirror; define sealed method raise-mirror (_port :: , sheet :: , mirror :: , #key activate? = #t) => () ignore(activate?); #f end method raise-mirror; define sealed method lower-mirror (_port :: , sheet :: , mirror :: ) => () #f end method lower-mirror; /// BitBlt define constant $function-map :: = make(, size: 16); begin $function-map[$boole-clr] := $BLACKNESS; $function-map[$boole-set] := $WHITENESS; $function-map[$boole-1] := $SRCCOPY; $function-map[$boole-2] := #xAA0029; $function-map[$boole-c1] := $NOTSRCCOPY; $function-map[$boole-c2] := $DSTINVERT; $function-map[$boole-and] := $SRCAND; $function-map[$boole-ior] := $SRCPAINT; $function-map[$boole-xor] := $SRCINVERT; $function-map[$boole-eqv] := #x990066; $function-map[$boole-nand] := #x7700E6; $function-map[$boole-nor] := $NOTSRCERASE; $function-map[$boole-andc1] := #x220326; $function-map[$boole-andc2] := $SRCERASE; $function-map[$boole-orc1] := $MERGEPAINT; $function-map[$boole-orc2] := #xBB0226 end; define sealed method do-copy-area (from-medium :: , from-x :: , from-y :: , width :: , height :: , to-medium :: , to-x :: , to-y :: , #key function = $boole-1) => () if (from-medium == to-medium) let sheet = medium-sheet(from-medium); let transform = sheet-device-transform(sheet); let hDC :: = get-DC(medium-drawable(from-medium)); with-device-coordinates (transform, from-x, from-y, to-x, to-y) with-device-distances (transform, width, height) BitBlt(hDC, to-x, to-y, width, height, hDC, from-x, from-y, $function-map[function]) end end else let from-sheet = medium-sheet(from-medium); let from-transform = sheet-device-transform(from-sheet); let to-sheet = medium-sheet(to-medium); let to-transform = sheet-device-transform(to-sheet); let from-hDC :: = get-DC(medium-drawable(from-medium)); let to-hDC :: = get-DC(medium-drawable(to-medium)); with-device-coordinates (from-transform, from-x, from-y) with-device-coordinates (to-transform, to-x, to-y) with-device-distances (from-transform, width, height) BitBlt(to-hDC, to-x, to-y, width, height, from-hDC, from-x, from-y, $function-map[function]) end end end end end method do-copy-area; define sealed method do-copy-area (from-medium :: , from-x :: , from-y :: , width :: , height :: , to-medium :: , to-x :: , to-y :: , #key function = $boole-1) => () let from-transform = sheet-device-transform(medium-sheet(from-medium)); let from-hDC :: = get-DC(medium-drawable(from-medium)); let to-hDC :: = get-DC(medium-drawable(to-medium)); with-device-coordinates (from-transform, from-x, from-y) with-device-distances (from-transform, width, height) BitBlt(to-hDC, to-x, to-y, width, height, from-hDC, from-x, from-y, $function-map[function]) end end end method do-copy-area; define sealed method do-copy-area (from-medium :: , from-x :: , from-y :: , width :: , height :: , pixmap :: , to-x :: , to-y :: , #key function = $boole-1) => () let from-transform = sheet-device-transform(medium-sheet(from-medium)); let from-hDC :: = get-DC(medium-drawable(from-medium)); let to-hDC :: = get-DC(pixmap); with-device-coordinates (from-transform, from-x, from-y) with-device-distances (from-transform, width, height) BitBlt(to-hDC, to-x, to-y, width, height, from-hDC, from-x, from-y, $function-map[function]) end end end method do-copy-area; define sealed method do-copy-area (from-medium :: , from-x :: , from-y :: , width :: , height :: , to-medium :: , to-x :: , to-y :: , #key function = $boole-1) => () let to-transform = sheet-device-transform(medium-sheet(to-medium)); let from-hDC :: = get-DC(medium-drawable(from-medium)); let to-hDC :: = get-DC(medium-drawable(to-medium)); with-device-coordinates (to-transform, to-x, to-y) BitBlt(to-hDC, to-x, to-y, width, height, from-hDC, from-x, from-y, $function-map[function]) end end method do-copy-area; define sealed method do-copy-area (pixmap :: , from-x :: , from-y :: , width :: , height :: , to-medium :: , to-x :: , to-y :: , #key function = $boole-1) => () let to-transform = sheet-device-transform(medium-sheet(to-medium)); let from-hDC :: = get-DC(pixmap); let to-hDC :: = get-DC(medium-drawable(to-medium)); with-device-coordinates (to-transform, to-x, to-y) BitBlt(to-hDC, to-x, to-y, width, height, from-hDC, from-x, from-y, $function-map[function]) end end method do-copy-area; define sealed method do-copy-area (from-medium :: , from-x :: , from-y :: , width :: , height :: , to-medium :: , to-x :: , to-y :: , #key function = $boole-1) => () let from-hDC :: = get-DC(medium-drawable(from-medium)); let to-hDC :: = get-DC(medium-drawable(to-medium)); BitBlt(to-hDC, to-x, to-y, width, height, from-hDC, from-x, from-y, $function-map[function]) end method do-copy-area; define sealed method do-copy-area (from-pixmap :: , from-x :: , from-y :: , width :: , height :: , to-pixmap :: , to-x :: , to-y :: , #key function = $boole-1) => () let from-hDC :: = get-DC(from-pixmap); let to-hDC :: = get-DC(to-pixmap); BitBlt(to-hDC, to-x, to-y, width, height, from-hDC, from-x, from-y, $function-map[function]) end method do-copy-area; /// Win32 images define open abstract primary class () sealed constant slot image-width :: , required-init-keyword: width:; sealed constant slot image-height :: , required-init-keyword: height:; //--- Type should be 'type-union(, , )' //--- except that 'make-gadget-control' expects to get a sealed constant slot image-resource-id :: , required-init-keyword: resource-id:; end class ; //--- This probably belongs somewhere else, and could be done with s define method concrete-resource-context (abstract-context == #"application", resource-type :: one-of(#"bitmap", #"icon")) => (concrete-context :: ) application-instance-handle() end method concrete-resource-context; define constant $null- :: = null-pointer(); define method concrete-resource-context (abstract-context == #"system", resource-type :: one-of(#"bitmap", #"icon")) => (concrete-context :: ) $null- end method concrete-resource-context; /// Win32 images -- bitmaps define sealed class () sealed constant slot image-handle :: false-or(), required-init-keyword: handle:; sealed slot %hBrush :: false-or() = #f; end class ; define sealed domain make (singleton()); define sealed domain initialize (); define sideways method read-image-as (class :: subclass(), resource-id :: , image-type == #"bitmap", #key width, height, error? = #f, resource-context = #"application") => (image :: false-or()) let handle :: = LoadImage(concrete-resource-context(resource-context, image-type), resource-id, $IMAGE-BITMAP, width | 0, height | 0, $LR-DEFAULTCOLOR); when (error?) check-result("LoadImage (bitmap)", handle) end; unless (null-pointer?(handle)) let handle = pointer-cast(, handle); let (width, height) = if (width & height) values(width, height) else let (default-width, default-height) = win32-bitmap-size(handle); values(width | default-width, height | default-height) end; make(, handle: handle, width: width, height: height, resource-id: resource-id) end end method read-image-as; // This handles ordinal bitmaps, OBM_BTNCORNERS, etc. define sideways method read-image-as (class :: subclass(), resource-id :: , image-type == #"bitmap", #key width, height, error? = #f, resource-context = #"application") => (image :: false-or()) assert(resource-id > 32700 & resource-id < 32767, "The value #o%o is not a valid ordinal bitmap constant", resource-id); let resource-id-as-pointer = make(, address: resource-id); let handle :: = LoadBitmap(concrete-resource-context(resource-context, image-type), resource-id-as-pointer); when (error?) check-result("LoadBitmap (bitmap)", handle) end; unless (null-pointer?(handle)) let (width, height) = if (width & height) values(width, height) else let (default-width, default-height) = win32-bitmap-size(handle); values(width | default-width, height | default-height) end; make(, handle: handle, width: width, height: height, //---*** This was 'resource-id: resource-id' //---*** The conversion to is just plain *wrong*, //---*** because trying to feed that string back to other Win32 //---*** resource functions won't get the same object, if it works at all. resource-id: integer-to-string(resource-id)) end end method read-image-as; define sealed method draw-image (medium :: , bitmap :: , x, y) => (record) let drawable = medium-drawable(medium); let hDC :: = get-DC(drawable); let transform = medium-device-transform(medium); with-device-coordinates (transform, x, y) let width = image-width(bitmap); let height = image-height(bitmap); let hBrush = bitmap.%hBrush | begin //---*** Loses in Win-95 when the image is bigger than 8x8 let hBrush = CreatePatternBrush(image-handle(bitmap)); check-result("CreatePatternBrush", hBrush); bitmap.%hBrush := hBrush; hBrush end; let pen :: = $null-hpen; let old-hBrush = SelectObject(hDC, hBrush); let old-hPen = SelectObject(hDC, pen); //--- '+ 1' because Windows doesn't draw the lower-right of rectangles Rectangle(hDC, x, y, x + width + 1, y + height + 1); SelectObject(hDC, old-hPen); SelectObject(hDC, old-hBrush) end; #f end method draw-image; define sealed method win32-bitmap-size (hBitmap :: ) => (width :: , height :: ) with-stack-structure (bitmap :: ) let result = GetObject(hBitmap, safe-size-of(), bitmap); unless (result = 0) ensure-no-error("GetObject") end; values(bitmap.bmWidth-value, bitmap.bmHeight-value) end end method win32-bitmap-size; /// Win32 images -- icons define sealed class () sealed constant slot image-handle :: false-or(), required-init-keyword: handle:; end class ; define sealed domain make (singleton()); define sealed domain initialize (); define sideways method read-image-as (class :: subclass(), resource-id :: , image-type == #"small-icon", #key width, height, error? = #f, resource-context = #"application") => (image :: false-or()) read-image-as(class, resource-id, #"icon", width: GetSystemMetrics($SM-CXSMICON), height: GetSystemMetrics($SM-CYSMICON), error?: error?, resource-context: resource-context) end method read-image-as; define sideways method read-image-as (class :: subclass(), resource-id :: , image-type == #"large-icon", #key width, height, error? = #f, resource-context = #"application") => (image :: false-or()) read-image-as(class, resource-id, #"icon", width: GetSystemMetrics($SM-CXICON), height: GetSystemMetrics($SM-CYICON), error?: error?, resource-context: resource-context) end method read-image-as; define sideways method read-image-as (class :: subclass(), resource-id :: , image-type == #"icon", #key width, height, error? = #f, resource-context = #"application") => (image :: false-or()) let handle :: = LoadImage(concrete-resource-context(resource-context, image-type), resource-id, $IMAGE-ICON, width | 0, height | 0, $LR-DEFAULTCOLOR); when (error?) check-result("LoadImage (icon)", handle) end; unless (null-pointer?(handle)) let handle = pointer-cast(, handle); let (width, height) = if (width & height) values(width, height) else let (default-width, default-height) = win32-icon-size(handle); values(width | default-width, height | default-height) end; make(, handle: handle, width: width, height: height, resource-id: resource-id) end end method read-image-as; define sealed method draw-image (medium :: , icon :: , x, y) => (record) let drawable = medium-drawable(medium); let hDC :: = get-DC(drawable); let transform = medium-device-transform(medium); with-device-coordinates (transform, x, y) let width = image-width(icon); let height = image-height(icon); let hbrush = mirror-background-brush(medium-sheet(medium), drawable); DrawIconEx(hDC, x, y, image-handle(icon), width, height, 0, hbrush, $DI-COMPAT) end; #f end method draw-image; define sealed method win32-icon-size (hIcon :: ) => (width :: , height :: ) with-stack-structure (icon-info :: ) let info = GetIconInfo(hIcon, icon-info); let bitmap = icon-info.hbmColor-value; if (null-pointer?(bitmap)) let mask = icon-info.hbmMask-value; win32-bitmap-size(mask) else win32-bitmap-size(bitmap) end end end method win32-icon-size;