| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_fpicker.hxx" |
| |
| //------------------------------------------------------------------------ |
| // includes |
| //------------------------------------------------------------------------ |
| |
| #include <tchar.h> |
| #include "helppopupwindow.hxx" |
| #include <osl/diagnose.h> |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| using rtl::OUString; |
| using osl::Mutex; |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| namespace /* private */ |
| { |
| |
| const LPTSTR CURRENT_INSTANCE = TEXT("CurrInst"); |
| |
| }; |
| |
| //------------------------------------------------------------------------ |
| // defines |
| //------------------------------------------------------------------------ |
| |
| #define HELPPOPUPWND_CLASS_NAME TEXT("hlppopupwnd###") |
| |
| const sal_Int32 MAX_CHARS_PER_LINE = 55; |
| |
| const sal_Int32 SHADOW_WIDTH = 6; |
| const sal_Int32 SHADOW_HEIGHT = 6; |
| const sal_Int32 SHADOW_OFFSET = 6; |
| const sal_Int32 YOFFSET = 20; |
| |
| const DWORD OUTER_FRAME_COLOR = 0; // black |
| const sal_Int32 OUTER_FRAME_WIDTH = 1; // pixel |
| |
| // it's the standard windows color of an inactive window border |
| const DWORD INNER_FRAME_COLOR = 0xC8D0D4; |
| const sal_Int32 INNER_FRAME_WIDTH = 1; // pixel |
| |
| //--------------------------------------------------- |
| // static member initialization |
| //--------------------------------------------------- |
| |
| osl::Mutex CHelpPopupWindow::s_Mutex; |
| ATOM CHelpPopupWindow::s_ClassAtom = 0; |
| sal_Int32 CHelpPopupWindow::s_RegisterWndClassCount = 0; |
| |
| //--------------------------------------------------- |
| // |
| //--------------------------------------------------- |
| |
| CHelpPopupWindow::CHelpPopupWindow( |
| HINSTANCE hInstance, |
| HWND hwndParent ) : |
| m_hMargins( 0 ), |
| m_vMargins( 0 ), |
| m_avCharWidth( 0 ), |
| m_avCharHeight( 0 ), |
| m_hwnd( NULL ), |
| m_hwndParent( hwndParent ), |
| m_hInstance( hInstance ), |
| m_hBitmapShadow( NULL ), |
| m_hBrushShadow( NULL ) |
| { |
| m_bWndClassRegistered = RegisterWindowClass( ) ? sal_True : sal_False; |
| |
| // create a pattern brush for the window shadow |
| WORD aPattern[] = { 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 }; |
| |
| m_hBitmapShadow = CreateBitmap( 8, 8, 1, 1, aPattern ); |
| m_hBrushShadow = CreatePatternBrush( m_hBitmapShadow ); |
| } |
| |
| //--------------------------------------------------- |
| // |
| //--------------------------------------------------- |
| |
| CHelpPopupWindow::~CHelpPopupWindow( ) |
| { |
| // remember: we don't have to destroy the |
| // preview window because it will be destroyed |
| // by it's parent window (the FileOpen dialog) |
| // but we have to unregister the window class |
| if ( m_bWndClassRegistered ) |
| UnregisterWindowClass( ); |
| |
| DeleteObject( m_hBitmapShadow ); |
| DeleteObject( m_hBrushShadow ); |
| } |
| |
| //--------------------------------------------------- |
| // |
| //--------------------------------------------------- |
| |
| void SAL_CALL CHelpPopupWindow::setText( const rtl::OUString& aHelpText ) |
| { |
| m_HelpText = aHelpText; |
| } |
| |
| //--------------------------------------------------- |
| // |
| //--------------------------------------------------- |
| |
| void SAL_CALL CHelpPopupWindow::show( sal_Int32 x, sal_Int32 y ) |
| { |
| OSL_ENSURE( NULL == m_hwnd, "method should not be called twice in sequence" ); |
| |
| // we create a window with length and heigth of 0 |
| // first in order to get a device context of this |
| // window, then we calculate the upper left corner |
| // and the dimensions and resize the window |
| |
| m_hwnd = CreateWindowEx( |
| NULL, |
| HELPPOPUPWND_CLASS_NAME, |
| NULL, |
| WS_POPUP, |
| 0, |
| 0, |
| 0, |
| 0, |
| m_hwndParent, |
| NULL, |
| m_hInstance, |
| (LPVOID)this ); |
| |
| OSL_ENSURE( m_hwnd, "creating help popup window failed" ); |
| |
| sal_Int32 cx_new; |
| sal_Int32 cy_new; |
| |
| adjustWindowSize( &cx_new, &cy_new ); |
| adjustWindowPos( x, y, cx_new, cy_new ); |
| |
| UpdateWindow( m_hwnd ); |
| ShowWindow( m_hwnd, SW_SHOW ); |
| } |
| |
| //--------------------------------------------------- |
| // |
| //--------------------------------------------------- |
| |
| HWND SAL_CALL CHelpPopupWindow::setParent( HWND hwndNewParent ) |
| { |
| HWND oldParent = m_hwndParent; |
| |
| m_hwndParent = hwndNewParent; |
| |
| return oldParent; |
| } |
| |
| //--------------------------------------------------- |
| // calculates the necessary dimensions of the popup |
| // window including the margins etc. |
| //--------------------------------------------------- |
| |
| void SAL_CALL CHelpPopupWindow::calcWindowRect( LPRECT lprect ) |
| { |
| OSL_ASSERT( m_hwnd && lprect ); |
| |
| SetRect( lprect, 0, 0, MAX_CHARS_PER_LINE * m_avCharWidth, 0 ); |
| |
| HDC hdc = GetDC( m_hwnd ); |
| |
| // set the font we are using later |
| HGDIOBJ oldFont = SelectObject( |
| hdc, GetStockObject( DEFAULT_GUI_FONT ) ); |
| |
| UINT nFormat = DT_WORDBREAK | DT_CALCRECT | DT_EXTERNALLEADING | DT_LEFT; |
| |
| if ( m_HelpText.getLength( ) <= MAX_CHARS_PER_LINE ) |
| nFormat |= DT_SINGLELINE; |
| |
| DrawText( |
| hdc, |
| reinterpret_cast<LPCTSTR>(m_HelpText.getStr( )), |
| m_HelpText.getLength( ), |
| lprect, |
| nFormat ); |
| |
| // add the necessary space for the frames |
| // and margins |
| |
| lprect->bottom += |
| m_vMargins + |
| SHADOW_HEIGHT + |
| OUTER_FRAME_WIDTH * 2 + |
| INNER_FRAME_WIDTH * 2; |
| |
| lprect->right += |
| SHADOW_WIDTH + |
| 2 * m_avCharWidth + |
| OUTER_FRAME_WIDTH * 2 + |
| INNER_FRAME_WIDTH * 2; |
| |
| SelectObject( hdc, oldFont ); |
| |
| ReleaseDC( m_hwnd, hdc ); |
| } |
| |
| //--------------------------------------------------- |
| // |
| //--------------------------------------------------- |
| |
| void SAL_CALL CHelpPopupWindow::adjustWindowSize( sal_Int32* cx_new, sal_Int32* cy_new ) |
| { |
| OSL_ASSERT( cx_new && cy_new ); |
| |
| RECT rect; |
| calcWindowRect( &rect ); |
| |
| // adjust the window size |
| SetWindowPos( |
| m_hwnd, |
| NULL, |
| 0, |
| 0, |
| rect.right, |
| rect.bottom, |
| SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER ); |
| |
| *cx_new = rect.right; |
| *cy_new = rect.bottom; |
| } |
| |
| //--------------------------------------------------- |
| // |
| //--------------------------------------------------- |
| |
| void SAL_CALL CHelpPopupWindow::adjustWindowPos( |
| sal_Int32 x, sal_Int32 y, sal_Int32 cx, sal_Int32 cy ) |
| { |
| int popX; |
| int popY; |
| int popWidth; |
| int popHeight; |
| |
| OSL_ASSERT( m_hwnd ); |
| |
| HDC hdc = GetDC( m_hwnd ); |
| |
| // assuming these are screen coordinates |
| popWidth = cx; |
| popHeight = cy; |
| popX = x - ( popWidth / 2 ); |
| popY = y - YOFFSET; |
| |
| int xScreen = GetDeviceCaps( hdc, HORZRES ); |
| int yScreen = GetDeviceCaps( hdc, VERTRES ); |
| |
| if (popX < 0) |
| popX = 0; |
| |
| if (popY < 0) |
| popY = 0; |
| |
| if ((popX + popWidth) > xScreen) |
| popX = xScreen - popWidth; |
| |
| if ((popY + popHeight) > yScreen) |
| popY = yScreen - popHeight; |
| |
| SetWindowPos( |
| m_hwnd, |
| NULL, |
| popX, |
| popY, |
| 0, |
| 0, |
| SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE ); |
| |
| ReleaseDC( m_hwnd, hdc ); |
| } |
| |
| //--------------------------------------------------- |
| // |
| //--------------------------------------------------- |
| |
| void SAL_CALL CHelpPopupWindow::onPaint( HWND hWnd, HDC hdc ) |
| { |
| RECT rc; |
| RECT rect; |
| HGDIOBJ hpen, hpenOld; |
| HGDIOBJ hbrOld; |
| COLORREF oldBkColor; |
| COLORREF oldTextColor; |
| HGDIOBJ oldFont; |
| HGDIOBJ oldBrush; |
| HGDIOBJ hBrush; |
| |
| GetClientRect( hWnd, &rc ); |
| |
| // draw the black border |
| |
| hBrush = CreateSolidBrush( GetSysColor( COLOR_INFOBK ) ); |
| oldBrush = SelectObject( hdc, hBrush ); |
| |
| hpen = CreatePen( PS_SOLID, 0, OUTER_FRAME_COLOR ); |
| hpenOld = SelectObject( hdc, hpen ); |
| |
| Rectangle( hdc, |
| rc.left + OUTER_FRAME_WIDTH, |
| rc.top + OUTER_FRAME_WIDTH, |
| rc.right - SHADOW_WIDTH, |
| rc.bottom - SHADOW_HEIGHT); |
| |
| SelectObject( hdc, oldBrush ); |
| SelectObject( hdc, hpenOld ); |
| |
| DeleteObject( hBrush ); |
| DeleteObject( hpen ); |
| |
| // draw a light gray border |
| |
| hBrush = CreateSolidBrush( GetSysColor( COLOR_INFOBK ) ); |
| oldBrush = SelectObject( hdc, hBrush ); |
| |
| hpen = CreatePen( PS_SOLID, 0, INNER_FRAME_COLOR ); |
| hpenOld = SelectObject( hdc, hpen ); |
| |
| Rectangle( hdc, |
| rc.left + OUTER_FRAME_WIDTH + 1, |
| rc.top + OUTER_FRAME_WIDTH + 1, |
| rc.right - SHADOW_WIDTH - OUTER_FRAME_WIDTH, |
| rc.bottom - SHADOW_HEIGHT - OUTER_FRAME_WIDTH ); |
| |
| SelectObject( hdc, oldBrush ); |
| SelectObject( hdc, hpenOld ); |
| |
| DeleteObject( hBrush ); |
| DeleteObject( hpen ); |
| |
| // Write some text to this window |
| |
| rect.left = rc.left + OUTER_FRAME_WIDTH + INNER_FRAME_WIDTH + 1 + m_hMargins; |
| rect.top = rc.top + OUTER_FRAME_WIDTH + INNER_FRAME_WIDTH + 1 + m_vMargins / 2; |
| rect.right = rc.right - SHADOW_WIDTH - OUTER_FRAME_WIDTH - INNER_FRAME_WIDTH - m_hMargins; |
| rect.bottom = rc.bottom - SHADOW_HEIGHT - OUTER_FRAME_WIDTH - INNER_FRAME_WIDTH - m_vMargins / 2; |
| |
| oldBkColor = SetBkColor( hdc, GetSysColor( COLOR_INFOBK ) ); |
| oldTextColor = SetTextColor( hdc, COLOR_INFOTEXT ); |
| |
| oldFont = SelectObject( hdc, GetStockObject( DEFAULT_GUI_FONT ) ); |
| |
| UINT nFormat = DT_WORDBREAK | DT_EXTERNALLEADING | DT_LEFT; |
| |
| if ( m_HelpText.getLength( ) <= MAX_CHARS_PER_LINE ) |
| nFormat |= DT_SINGLELINE; |
| |
| DrawText( |
| hdc, |
| (LPWSTR)m_HelpText.getStr( ), |
| m_HelpText.getLength( ), |
| &rect, |
| nFormat ); |
| |
| SelectObject( hdc, oldFont ); |
| SetTextColor( hdc, oldTextColor ); |
| SetBkColor( hdc, oldBkColor ); |
| |
| // set text color and text background color |
| // see MSDN PatBlt |
| |
| oldBkColor = SetBkColor( hdc, RGB( 0, 0, 0 ) ); |
| oldTextColor = SetTextColor( hdc, RGB( 255, 255, 255 ) ); |
| |
| // Get our brush for the shadow |
| |
| UnrealizeObject( m_hBrushShadow ); |
| hbrOld = SelectObject( hdc, m_hBrushShadow ); |
| |
| // bottom shadow |
| |
| PatBlt(hdc, |
| rc.left + SHADOW_OFFSET, |
| rc.bottom - SHADOW_HEIGHT, |
| rc.right - SHADOW_OFFSET - SHADOW_WIDTH, |
| SHADOW_HEIGHT, |
| 0xA000C9); |
| |
| // right-side shadow |
| |
| PatBlt(hdc, |
| rc.right - SHADOW_WIDTH, |
| rc.top + SHADOW_OFFSET, |
| SHADOW_WIDTH, |
| rc.bottom - SHADOW_OFFSET, |
| 0xA000C9); |
| |
| SelectObject(hdc, hbrOld); |
| SetTextColor( hdc, oldTextColor ); |
| SetBkColor( hdc, oldBkColor ); |
| } |
| |
| //--------------------------------------------------- |
| // |
| //--------------------------------------------------- |
| |
| void SAL_CALL CHelpPopupWindow::onNcDestroy() |
| { |
| m_hwnd = NULL; |
| } |
| |
| //--------------------------------------------------- |
| // |
| //--------------------------------------------------- |
| |
| void SAL_CALL CHelpPopupWindow::onCreate( HWND hwnd ) |
| { |
| m_hwnd = hwnd; |
| |
| HDC hdc = GetDC( m_hwnd ); |
| |
| HGDIOBJ oldFont = SelectObject( |
| hdc, GetStockObject( DEFAULT_GUI_FONT ) ); |
| |
| TEXTMETRIC tm; |
| GetTextMetrics( hdc, &tm ); |
| |
| m_avCharWidth = tm.tmAveCharWidth; |
| m_avCharHeight = tm.tmHeight; |
| |
| if ( 0 == m_hMargins ) |
| m_hMargins = m_avCharWidth; |
| |
| if ( 0 == m_vMargins ) |
| m_vMargins = m_avCharHeight; |
| |
| SelectObject( hdc, oldFont ); |
| |
| ReleaseDC( m_hwnd, hdc ); |
| } |
| |
| //--------------------------------------------------- |
| // |
| //--------------------------------------------------- |
| |
| LRESULT CALLBACK CHelpPopupWindow::WndProc( |
| HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) |
| { |
| LRESULT lResult = 0; |
| |
| switch ( uMsg ) |
| { |
| case WM_CREATE: |
| { |
| LPCREATESTRUCT lpcs = |
| reinterpret_cast< LPCREATESTRUCT >( lParam ); |
| |
| OSL_ASSERT( lpcs->lpCreateParams ); |
| |
| CHelpPopupWindow* pImpl = reinterpret_cast< CHelpPopupWindow* >( |
| lpcs->lpCreateParams ); |
| |
| // connect the instance handle to the window |
| SetProp( hWnd, CURRENT_INSTANCE, pImpl ); |
| |
| pImpl->onCreate( hWnd ); |
| |
| // capture mouse and keybord events |
| SetCapture( hWnd ); |
| } |
| break; |
| |
| case WM_PAINT: |
| { |
| CHelpPopupWindow* pImpl = reinterpret_cast< CHelpPopupWindow* >( |
| GetProp( hWnd, CURRENT_INSTANCE ) ); |
| |
| OSL_ASSERT( pImpl ); |
| |
| PAINTSTRUCT ps; |
| |
| BeginPaint(hWnd, &ps); |
| pImpl->onPaint( hWnd, ps.hdc ); |
| EndPaint(hWnd, &ps); |
| } |
| break; |
| |
| case WM_NCDESTROY: |
| { |
| // RemoveProp returns the saved value on success |
| CHelpPopupWindow* pImpl = reinterpret_cast< CHelpPopupWindow* >( |
| RemoveProp( hWnd, CURRENT_INSTANCE ) ); |
| |
| OSL_ASSERT( pImpl ); |
| |
| pImpl->onNcDestroy(); |
| } |
| break; |
| |
| case WM_LBUTTONDOWN: |
| case WM_KEYDOWN: |
| case WM_SYSKEYDOWN: |
| case WM_MBUTTONDOWN: |
| case WM_RBUTTONDOWN: |
| ReleaseCapture(); |
| DestroyWindow(hWnd); |
| break; |
| |
| default: |
| return DefWindowProc(hWnd, uMsg, wParam, lParam); |
| } |
| |
| return lResult; |
| } |
| |
| //--------------------------------------------------- |
| // |
| //--------------------------------------------------- |
| |
| ATOM SAL_CALL CHelpPopupWindow::RegisterWindowClass( ) |
| { |
| osl::MutexGuard aGuard( s_Mutex ); |
| |
| if ( 0 == s_ClassAtom ) |
| { |
| // register the window class |
| WNDCLASSEX wndClsEx; |
| |
| ZeroMemory(&wndClsEx, sizeof(wndClsEx)); |
| |
| wndClsEx.cbSize = sizeof(wndClsEx); |
| wndClsEx.lpfnWndProc = CHelpPopupWindow::WndProc; |
| wndClsEx.hInstance = m_hInstance; |
| wndClsEx.hCursor = LoadCursor(NULL, IDC_ARROW); |
| wndClsEx.hbrBackground = (HBRUSH)GetStockObject( NULL_BRUSH ); |
| wndClsEx.lpszClassName = HELPPOPUPWND_CLASS_NAME; |
| |
| // register the preview window class |
| // !!! Win95 - the window class will be unregistered automaticly |
| // if the dll is unloaded |
| // Win2000 - the window class must be unregistered manually |
| // if the dll is unloaded |
| s_ClassAtom = RegisterClassEx( &wndClsEx ); |
| OSL_ASSERT(s_ClassAtom); |
| } |
| |
| // increment the register class counter |
| // so that we keep track of the number |
| // of class registrations |
| if (0 != s_ClassAtom) |
| s_RegisterWndClassCount++; |
| |
| return s_ClassAtom; |
| } |
| |
| //--------------------------------------------------- |
| // |
| //--------------------------------------------------- |
| |
| void SAL_CALL CHelpPopupWindow::UnregisterWindowClass( ) |
| { |
| osl::MutexGuard aGuard( s_Mutex ); |
| |
| OSL_ASSERT( ( (0 != s_ClassAtom) && (s_RegisterWndClassCount > 0)) || |
| ( (0 == s_ClassAtom) && (0 == s_RegisterWndClassCount) ) ); |
| |
| // update the register class counter |
| // and unregister the window class if |
| // counter drops to zero |
| if ( 0 != s_ClassAtom ) |
| { |
| s_RegisterWndClassCount--; |
| OSL_ASSERT( s_RegisterWndClassCount >= 0 ); |
| } |
| |
| if ( 0 == s_RegisterWndClassCount ) |
| { |
| if ( !UnregisterClass( |
| (LPCTSTR)MAKELONG( s_ClassAtom, 0 ), m_hInstance ) ) |
| { |
| OSL_ENSURE( false, "unregister window class failed" ); |
| } |
| |
| s_ClassAtom = 0; |
| } |
| } |