Skip to content

Commit

Permalink
Fix high DPI issues
Browse files Browse the repository at this point in the history
  • Loading branch information
gyk committed Dec 17, 2021
1 parent 6a70fca commit 888756d
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 37 deletions.
19 changes: 11 additions & 8 deletions native-windows-gui/src/resources/image_list.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::ptr;

use winapi::um::commctrl::{HIMAGELIST, ImageList_AddMasked};
use winapi::shared::windef::{HICON, HBITMAP};

use crate::{Bitmap, Icon, NwgError};
use std::ptr;
use crate::win32::high_dpi;


const NOT_BOUND: &'static str = "ImageList is not yet bound to a winapi object";
Expand All @@ -12,7 +15,7 @@ Image lists are used in controls such as tabs container and tree view in order t
There are two kinds of image list in Winapi: masked. This is a wrapper over the masked type.
Image list and the method that use them in controls are behind the "image-list" feature.
Image list and the method that use them in controls are behind the "image-list" feature.
**Builder parameters:**
* `size`: The size size of the images in the image list. Default `(32, 32)`
Expand Down Expand Up @@ -55,7 +58,7 @@ impl ImageList {
let mut size = (0, 0);
unsafe { ImageList_GetIconSize(self.handle, &mut size.0, &mut size.1); }

size
unsafe { high_dpi::physical_to_logical(size.0, size.1) }
}

/// Sets the size of the image list. This clears all current image data.
Expand All @@ -64,7 +67,7 @@ impl ImageList {

if self.handle.is_null() { panic!("{}", NOT_BOUND); }

let (w, h) = size;
let (w, h) = unsafe { high_dpi::logical_to_physical(size.0, size.1) };
unsafe { ImageList_SetIconSize(self.handle, w, h); }
}

Expand Down Expand Up @@ -116,7 +119,7 @@ impl ImageList {
unsafe {
let mut info: ICONINFO = ::std::mem::zeroed();
GetIconInfo(icon.handle as _, &mut info);

let i = ImageList_AddMasked(self.handle, info.hbmColor, 0);

DeleteObject(info.hbmMask as _);
Expand Down Expand Up @@ -165,7 +168,7 @@ impl ImageList {

if self.handle.is_null() { panic!("{}", NOT_BOUND); }
if bitmap.handle.is_null() { panic!("Bitmap was not initialized"); }

unsafe { ImageList_Replace(self.handle, index, bitmap.handle as HBITMAP, ptr::null_mut()); }
}

Expand Down Expand Up @@ -236,7 +239,7 @@ impl ImageListBuilder {
use winapi::um::commctrl::{ImageList_Create, ILC_COLOR32, ILC_MASK};

unsafe {
let (w, h) = self.size;
let (w, h) = high_dpi::logical_to_physical(self.size.0, self.size.1);
let handle = ImageList_Create(w, h, ILC_COLOR32 | ILC_MASK, self.initial, self.grow);
if handle.is_null() {
return Err(NwgError::resource_create("Failed to create image list"));
Expand All @@ -245,7 +248,7 @@ impl ImageListBuilder {
list.handle = handle;
list.owned = true;
}

Ok(())
}

Expand Down
63 changes: 34 additions & 29 deletions native-windows-gui/src/win32/resources_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use winapi::ctypes::c_int;
use winapi::um::winnt::HANDLE;

use crate::resources::OemImage;
use crate::win32::high_dpi;
use super::base_helper::{get_system_error, to_utf16};

#[allow(unused_imports)] use std::{ptr, mem};
Expand All @@ -25,23 +26,23 @@ pub fn is_bitmap(handle: HBITMAP) -> bool {

pub fn destroy_icon(icon: HANDLE) {
unsafe { winapi::um::winuser::DestroyIcon(icon as _); }
}
}

pub fn destroy_cursor(cursor: HANDLE) {
unsafe { winapi::um::winuser::DestroyCursor(cursor as _); }
}
}

pub fn destroy_obj(obj: HANDLE) {
unsafe { winapi::um::wingdi::DeleteObject(obj as _); }
}
}

pub unsafe fn build_font(
size: i32,
weight: u32,
style: [bool; 3],
family_name: Option<&str>,
) -> Result<HFONT, NwgError>
{
) -> Result<HFONT, NwgError>
{
use winapi::um::wingdi::{DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH};
use winapi::um::wingdi::CreateFontW;
let [use_italic, use_underline, use_strikeout] = style;
Expand All @@ -56,7 +57,7 @@ pub unsafe fn build_font(
family_name_ptr = ptr::null();
}

let (size, _) = super::high_dpi::logical_to_physical(size as i32, 0);
let (size, _) = high_dpi::logical_to_physical(size as i32, 0);

let handle = CreateFontW(
size as c_int, // nHeight
Expand Down Expand Up @@ -95,8 +96,9 @@ pub unsafe fn build_image<'a>(

let filepath = to_utf16(source);
let (width, height) = size.unwrap_or((0,0));
let (width, height) = high_dpi::logical_to_physical(width as i32, height as i32);

let mut handle = LoadImageW(ptr::null_mut(), filepath.as_ptr(), image_type, width as i32, height as i32, LR_LOADFROMFILE);
let mut handle = LoadImageW(ptr::null_mut(), filepath.as_ptr(), image_type, width, height, LR_LOADFROMFILE);
if handle.is_null() {
let (code, _) = get_system_error();
if code == 2 && !strict {
Expand All @@ -116,7 +118,7 @@ pub unsafe fn build_image<'a>(
},
_ => { unreachable!() }
};

}
}

Expand All @@ -138,15 +140,16 @@ pub unsafe fn build_image_decoder<'a>(
use crate::ImageDecoder;

let decoder = ImageDecoder::new()?;

let mut image_frame = decoder
.from_filename(source)?
.frame(0)?;

if let Some((width, height)) = size {
image_frame = decoder.resize_image(&image_frame, [width, height])?;
let (width, height) = high_dpi::logical_to_physical(width as i32, height as i32);
image_frame = decoder.resize_image(&image_frame, [width as u32, height as u32])?;
}

let mut bitmap = image_frame.as_bitmap()?;

bitmap.owned = false;
Expand All @@ -163,15 +166,16 @@ pub unsafe fn build_image_decoder_from_memory<'a>(
use crate::ImageDecoder;

let decoder = ImageDecoder::new()?;

let mut image_frame = decoder
.from_stream(src)?
.frame(0)?;

if let Some((width, height)) = size {
image_frame = decoder.resize_image(&image_frame, [width, height])?;
let (width, height) = high_dpi::logical_to_physical(width as i32, height as i32);
image_frame = decoder.resize_image(&image_frame, [width as u32, height as u32])?;
}

let mut bitmap = image_frame.as_bitmap()?;

bitmap.owned = false;
Expand All @@ -182,13 +186,14 @@ pub unsafe fn build_image_decoder_from_memory<'a>(
pub unsafe fn build_oem_image(
source: OemImage,
size: Option<(u32, u32)>,
) -> Result<HANDLE, NwgError>
) -> Result<HANDLE, NwgError>
{
use winapi::um::winuser::{LR_DEFAULTSIZE, LR_SHARED, IMAGE_ICON, IMAGE_CURSOR, IMAGE_BITMAP};
use winapi::um::winuser::LoadImageW;
use winapi::shared::ntdef::LPCWSTR;

let (width, height) = size.unwrap_or((0,0));
let (width, height) = high_dpi::logical_to_physical(width as i32, height as i32);

let (c_res_type, res_identifier) = match source {
OemImage::Bitmap(b) => {
Expand All @@ -208,7 +213,7 @@ pub unsafe fn build_oem_image(
LR_SHARED
};

let handle = LoadImageW(ptr::null_mut(), res_identifier, c_res_type, width as i32, height as i32, flags);
let handle = LoadImageW(ptr::null_mut(), res_identifier, c_res_type, width, height, flags);

if handle.is_null() {
Err( NwgError::resource_create("Failed to create image from system resource") )
Expand All @@ -218,7 +223,7 @@ pub unsafe fn build_oem_image(
}


/**
/**
Create a bitmap from memory. Only supports bitmap. Enable the `image-decoder` to load more image type from memory
The memory must contain the whole file (including the bitmap header).
*/
Expand Down Expand Up @@ -256,7 +261,7 @@ pub unsafe fn bitmap_from_memory(source: &[u8]) -> Result<HANDLE, NwgError> {

let header = BITMAPINFOHEADER {
biSize: mem::size_of::<BITMAPINFOHEADER>() as DWORD,
biWidth: w as LONG, biHeight: h as LONG,
biWidth: w as LONG, biHeight: h as LONG,
biPlanes: 1, biBitCount: 24, biCompression: BI_RGB,
biSizeImage: (w * h * 3) as u32,
biXPelsPerMeter: 0, biYPelsPerMeter: 0,
Expand All @@ -278,7 +283,7 @@ pub unsafe fn bitmap_from_memory(source: &[u8]) -> Result<HANDLE, NwgError> {
return Ok(bitmap as HANDLE);
}

/**
/**
Create a bitmap from memory. The source can be any image type supported by the windows imaging component.
The memory must contain the whole file (including the file header).
*/
Expand Down Expand Up @@ -343,7 +348,7 @@ pub unsafe fn create_file_dialog<'a, 'b>(
multiselect: bool,
default_folder: Option<String>,
filters: Option<String>
) -> Result<*mut IFileDialog, NwgError>
) -> Result<*mut IFileDialog, NwgError>
{
use winapi::um::shobjidl_core::{CLSID_FileSaveDialog, CLSID_FileOpenDialog};
use winapi::um::shobjidl::{FOS_PICKFOLDERS, FOS_ALLOWMULTISELECT, FOS_FORCEFILESYSTEM};
Expand All @@ -366,18 +371,18 @@ pub unsafe fn create_file_dialog<'a, 'b>(

// Set dialog options
if file_dialog.GetOptions(&mut flags) != S_OK {
file_dialog.Release();
file_dialog.Release();
return Err(NwgError::file_dialog("Filedialog creation failed"));
}

let use_dir = if action == FileDialogAction::OpenDirectory { FOS_PICKFOLDERS } else { 0 };
let multiselect = if multiselect { FOS_ALLOWMULTISELECT } else { 0 };
if file_dialog.SetOptions(flags | FOS_FORCEFILESYSTEM | use_dir | multiselect) != S_OK {
file_dialog.Release();
return Err(NwgError::file_dialog("Filedialog creation failed"));
}


// Set the default folder
match &default_folder {
&Some(ref f) => match file_dialog_set_default_folder(file_dialog, f) {
Expand Down Expand Up @@ -424,7 +429,7 @@ pub unsafe fn file_dialog_set_default_folder<'a>(dialog: &mut IFileDialog, folde

let shellitem = &mut *shellitem;
let mut file_properties: SFGAOF = 0;

let results = shellitem.GetAttributes(SFGAO_FOLDER, &mut file_properties);

if results != S_OK && results != S_FALSE {
Expand Down Expand Up @@ -466,7 +471,7 @@ pub unsafe fn file_dialog_set_filters<'a>(dialog: &mut IFileDialog, filters: &'a

let (_name, _filter) = f.split_at(end.unwrap());
let (name, filter) = (to_utf16(_name), to_utf16(&_filter[1.._filter.len()-1]));

raw_filters.push(COMDLG_FILTERSPEC{ pszName: name.as_ptr(), pszSpec: filter.as_ptr() });
keep_alive.push( (name, filter) );
}
Expand All @@ -483,7 +488,7 @@ pub unsafe fn file_dialog_set_filters<'a>(dialog: &mut IFileDialog, filters: &'a
#[cfg(feature = "file-dialog")]
pub unsafe fn filedialog_get_item(dialog: &mut IFileDialog) -> Result<OsString, NwgError> {
use winapi::shared::winerror::S_OK;

let mut _item: *mut IShellItem = ptr::null_mut();

if dialog.GetResult(&mut _item) != S_OK {
Expand All @@ -500,7 +505,7 @@ pub unsafe fn filedialog_get_item(dialog: &mut IFileDialog) -> Result<OsString,
pub unsafe fn filedialog_get_items(dialog: &mut IFileOpenDialog) -> Result<Vec<OsString>, NwgError> {
use winapi::um::shobjidl::IShellItemArray;
use winapi::shared::{winerror::S_OK, minwindef::DWORD};

let mut _item: *mut IShellItem = ptr::null_mut();
let mut _items: *mut IShellItemArray = ptr::null_mut();

Expand All @@ -511,7 +516,7 @@ pub unsafe fn filedialog_get_items(dialog: &mut IFileOpenDialog) -> Result<Vec<O
let items = &mut *_items;
let mut count: DWORD = 0;
items.GetCount(&mut count);

let mut item_names: Vec<OsString> = Vec::with_capacity(count as usize);
for i in 0..count {
items.GetItemAt(i, &mut _item);
Expand Down Expand Up @@ -560,7 +565,7 @@ pub unsafe fn file_dialog_options(dialog: &mut IFileDialog) -> Result<u32, NwgEr
#[cfg(feature = "file-dialog")]
pub unsafe fn toggle_dialog_flags(dialog: &mut IFileDialog, flag: u32, enabled: bool) -> Result<(), NwgError> {
use winapi::shared::winerror::S_OK;

let mut flags = file_dialog_options(dialog)?;
flags = match enabled {
true => flags | flag,
Expand Down

0 comments on commit 888756d

Please sign in to comment.