1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <docholder.hxx>
21 #include <syswinwrapper.hxx>
22 
23 /*
24  * CWindow::CWindow
25  * CWindow::~CWindow
26  *
27  * Constructor Parameters:
28  *  hInst           HINSTANCE of the task owning us.
29  */
30 
31 
32 using namespace winwrap;
33 
34 
35 #define HWWL_STRUCTURE                  0
36 
37 //Notification codes for WM_COMMAND messages
38 #define HWN_BORDERDOUBLECLICKED         1
39 #define CBHATCHWNDEXTRA                 (sizeof(LONG))
40 #define SZCLASSHATCHWIN                 L"hatchwin"
41 
42 typedef CHatchWin *PCHatchWin;
43 
CWindow(HINSTANCE hInst)44 winwrap::CWindow::CWindow(HINSTANCE hInst)
45 {
46     m_hInst=hInst;
47     m_hWnd=nullptr;
48     return;
49 }
50 
~CWindow()51 winwrap::CWindow::~CWindow()
52 {
53     if (IsWindow(m_hWnd))
54         DestroyWindow(m_hWnd);
55 
56     return;
57 }
58 
59 
60 /*
61  * CWindow::Window
62  *
63  * Purpose:
64  *  Returns the window handle associated with this object.
65  *
66  * Return Value:
67  *  HWND            Window handle for this object
68  */
69 
Window()70 HWND winwrap::CWindow::Window()
71 {
72     return m_hWnd;
73 }
74 
75 
76 /*
77  * CWindow::Instance
78  *
79  * Purpose:
80  *  Returns the instance handle associated with this object.
81  *
82  * Return Value:
83  *  HINSTANCE       Instance handle of the module stored here.
84  */
85 
Instance()86 HINSTANCE winwrap::CWindow::Instance()
87 {
88     return m_hInst;
89 }
90 
91 /*
92  * HatchWindowRegister
93  *
94  * Purpose:
95  *  Registers the hatch window class for use with CHatchWin.
96  *
97  * Parameters:
98  *  hInst           HINSTANCE under which to register.
99  *
100  * Return Value:
101  *  BOOL            TRUE if successful, FALSE otherwise.
102  */
103 
HatchWindowRegister(HINSTANCE hInst)104 BOOL winwrap::HatchWindowRegister(HINSTANCE hInst)
105 {
106     WNDCLASSW    wc;
107 
108     //Must have CS_DBLCLKS for border!
109     wc.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
110     wc.hInstance     = hInst;
111     wc.cbClsExtra    = 0;
112     wc.lpfnWndProc   = HatchWndProc;
113     wc.cbWndExtra    = CBHATCHWNDEXTRA;
114     wc.hIcon         = nullptr;
115     wc.hCursor       = LoadCursor(nullptr, IDC_ARROW);
116     wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1);
117     wc.lpszMenuName  = nullptr;
118     wc.lpszClassName = SZCLASSHATCHWIN;
119 
120     return RegisterClassW(&wc);
121 }
122 
123 
124 /*
125  * CHatchWin:CHatchWin
126  * CHatchWin::~CHatchWin
127  *
128  * Constructor Parameters:
129  *  hInst           HINSTANCE of the application we're in.
130  */
131 
CHatchWin(HINSTANCE hInst,const DocumentHolder * pDocHolder)132 CHatchWin::CHatchWin(HINSTANCE hInst,const DocumentHolder* pDocHolder)
133     : CWindow(hInst),
134       m_aTracker()
135 {
136     m_hWnd=nullptr;
137     m_hWndKid=nullptr;
138     m_hWndAssociate=nullptr;
139     m_uID=0;
140 
141     m_dBorderOrg=GetProfileIntW(L"windows"
142                                , L"OleInPlaceBorderWidth"
143                                , HATCHWIN_BORDERWIDTHDEFAULT);
144 
145     m_dBorder=m_dBorderOrg;
146     SetRect(&m_rcPos, 0, 0, 0, 0);
147     SetRect(&m_rcClip, 0, 0, 0, 0);
148 
149     m_pDocHolder = pDocHolder;
150     return;
151 }
152 
153 
~CHatchWin()154 CHatchWin::~CHatchWin()
155 {
156     /*
157      * Chances are this was already destroyed when a document
158      * was destroyed.
159      */
160     if (nullptr!=m_hWnd && IsWindow(m_hWnd))
161         DestroyWindow(m_hWnd);
162 
163     return;
164 }
165 
166 
167 /*
168  * CHatchWin::Init
169  *
170  * Purpose:
171  *  Instantiates a hatch window within a given parent with a
172  *  default rectangle.  This is not initially visible.
173  *
174  * Parameters:
175  *  hWndParent      HWND of the parent of this window
176  *  uID             WORD identifier for this window (send in
177  *                  notifications to associate window).
178  *  hWndAssoc       HWND of the initial associate.
179  *
180  * Return Value:
181  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
182  */
183 
Init(HWND hWndParent,WORD uID,HWND hWndAssoc)184 BOOL CHatchWin::Init(HWND hWndParent, WORD uID, HWND hWndAssoc)
185 {
186     m_hWndParent = hWndParent;
187     m_hWnd=CreateWindowExW(
188         WS_EX_NOPARENTNOTIFY, SZCLASSHATCHWIN
189         , SZCLASSHATCHWIN, WS_CHILD | WS_CLIPSIBLINGS
190         | WS_CLIPCHILDREN, 0, 0, 100, 100, hWndParent
191         , reinterpret_cast<HMENU>(UINT_PTR(uID)), m_hInst, this);
192 
193     m_uID=uID;
194     m_hWndAssociate=hWndAssoc;
195 
196     return (nullptr!=m_hWnd);
197 }
198 
199 
SetTrans()200 void CHatchWin::SetTrans()
201 {
202     HRGN hrgn = CreateRectRgn(0,0,0,0);
203     SetWindowRgn(m_hWnd,hrgn,true);
204 }
205 
206 /*
207  * CHatchWin::HwndAssociateSet
208  * CHatchWin::HwndAssociateGet
209  *
210  * Purpose:
211  *  Sets (Set) or retrieves (Get) the associate window of the
212  *  hatch window.
213  *
214  * Parameters: (Set only)
215  *  hWndAssoc       HWND to set as the associate.
216  *
217  * Return Value:
218  *  HWND            Previous (Set) or current (Get) associate
219  *                  window.
220  */
221 
HwndAssociateSet(HWND hWndAssoc)222 HWND CHatchWin::HwndAssociateSet(HWND hWndAssoc)
223 {
224     HWND    hWndT=m_hWndAssociate;
225 
226     m_hWndAssociate=hWndAssoc;
227     return hWndT;
228 }
229 
230 
HwndAssociateGet()231 HWND CHatchWin::HwndAssociateGet()
232 {
233     return m_hWndAssociate;
234 }
235 
236 
237 /*
238  * CHatchWin::RectsSet
239  *
240  * Purpose:
241  *  Changes the size and position of the hatch window and the child
242  *  window within it using a position rectangle for the child and
243  *  a clipping rectangle for the hatch window and child.  The hatch
244  *  window occupies prcPos expanded by the hatch border and clipped
245  *  by prcClip.  The child window is fit to prcPos to give the
246  *  proper scaling, but it clipped to the hatch window which
247  *  therefore clips it to prcClip without affecting the scaling.
248  *
249  * Parameters:
250  *  prcPos          LPRECT providing the position rectangle.
251  *  prcClip         LPRECT providing the clipping rectangle.
252  *
253  * Return Value:
254  *  None
255  */
256 
RectsSet(LPRECT prcPos,LPRECT prcClip)257 void CHatchWin::RectsSet(LPRECT prcPos, LPRECT prcClip)
258 {
259     RECT    rc;
260     RECT    rcPos;
261 
262     m_rcPos=*prcPos;
263     m_rcClip=*prcClip;
264 
265     //Calculate the rectangle for the hatch window, then clip it.
266     rcPos=*prcPos;
267     InflateRect(&rcPos, m_dBorder, m_dBorder);
268     IntersectRect(&rc, &rcPos, prcClip);
269 
270     SetWindowPos(m_hWnd, nullptr, rc.left, rc.top, rc.right-rc.left
271                  , rc.bottom-rc.top, SWP_NOZORDER | SWP_NOACTIVATE);
272 
273     /*
274      * Set the rectangle of the child window to be at m_dBorder
275      * from the top and left but with the same size as prcPos
276      * contains.  The hatch window will clip it.
277      */
278 //     SetWindowPos(m_hWndKid, NULL, rcPos.left-rc.left+m_dBorder
279 //                  , rcPos.top-rc.top+m_dBorder, prcPos->right-prcPos->left
280 //                  , prcPos->bottom-prcPos->top, SWP_NOZORDER | SWP_NOACTIVATE);
281 
282     RECT newRC;
283     GetClientRect(m_hWnd,&newRC);
284     m_aTracker = Tracker(
285         &newRC,
286         Tracker::hatchInside |
287         Tracker::hatchedBorder |
288         Tracker::resizeInside
289     );
290 
291     return;
292 }
293 
294 
295 /*
296  * CHatchWin::ChildSet
297  *
298  * Purpose:
299  *  Assigns a child window to this hatch window.
300  *
301  * Parameters:
302  *  hWndKid         HWND of the child window.
303  *
304  * Return Value:
305  *  None
306  */
307 
ChildSet(HWND hWndKid)308 void CHatchWin::ChildSet(HWND hWndKid)
309 {
310     m_hWndKid=hWndKid;
311 
312     if (nullptr!=hWndKid)
313     {
314         SetParent(hWndKid, m_hWnd);
315 
316         //Ensure this is visible when the hatch window becomes visible.
317         ShowWindow(hWndKid, SW_SHOW);
318     }
319 
320     return;
321 }
322 
323 
324 /*
325  * CHatchWin::ShowHatch
326  *
327  * Purpose:
328  *  Turns hatching on and off; turning the hatching off changes
329  *  the size of the window to be exactly that of the child, leaving
330  *  everything else the same.  The result is that we don't have
331  *  to turn off drawing because our own WM_PAINT will never be
332  *  called.
333  *
334  * Parameters:
335  *  fHatch          BOOL indicating to show (TRUE) or hide (FALSE)
336                     the hatching.
337  *
338  * Return Value:
339  *  None
340  */
341 
ShowHatch(BOOL fHatch)342 void CHatchWin::ShowHatch(BOOL fHatch)
343 {
344     /*
345      * All we have to do is set the border to zero and
346      * call SetRects again with the last rectangles the
347      * child sent to us.
348      */
349     m_dBorder=fHatch ? m_dBorderOrg : 0;
350     RectsSet(&m_rcPos, &m_rcClip);
351     return;
352 }
353 
354 
355 /*
356  * HatchWndProc
357  *
358  * Purpose:
359  *  Standard window procedure for the Hatch Window
360  */
361 
HatchWndProc(HWND hWnd,UINT iMsg,WPARAM wParam,LPARAM lParam)362 LRESULT APIENTRY winwrap::HatchWndProc(
363     HWND hWnd, UINT iMsg
364     , WPARAM wParam, LPARAM lParam)
365 {
366     PCHatchWin  phw;
367     HDC         hDC;
368     PAINTSTRUCT ps;
369 
370     phw=reinterpret_cast<PCHatchWin>(GetWindowLongPtrW(hWnd, HWWL_STRUCTURE));
371     POINT ptMouse;
372 
373     switch (iMsg)
374     {
375         case WM_CREATE:
376             phw=static_cast<PCHatchWin>(reinterpret_cast<LPCREATESTRUCT>(lParam)->lpCreateParams);
377             SetWindowLongPtrW(hWnd, HWWL_STRUCTURE, reinterpret_cast<LONG_PTR>(phw));
378             break;
379         case WM_PAINT:
380             hDC=BeginPaint(hWnd,&ps);
381             //Always draw the hatching.
382             phw->m_aTracker.Draw(hDC);
383             EndPaint(hWnd,&ps);
384             break;
385         case WM_LBUTTONDOWN:
386             GetCursorPos(&ptMouse);
387             ScreenToClient(hWnd,&ptMouse);
388 
389             // track in case we have to
390             if(phw->m_aTracker.Track(hWnd,ptMouse,FALSE,GetParent(hWnd)))
391             {
392                 RECT aRect = phw->m_aTracker.m_rect;
393                 TransformRect(&aRect,hWnd,GetParent(hWnd));
394                 phw->m_pDocHolder->OnPosRectChanged(&aRect);
395             }
396             break;
397         case WM_LBUTTONUP:
398         case WM_MOUSEMOVE:
399             GetCursorPos(&ptMouse);
400             ScreenToClient(hWnd,&ptMouse);
401             phw->m_aTracker.SetCursor(hWnd,HTCLIENT);
402             break;
403         case WM_SETFOCUS:
404             //We need this since the container will SetFocus to us.
405             if (nullptr!=phw->m_hWndKid)
406                 SetFocus(phw->m_hWndKid);
407 
408             break;
409         case WM_LBUTTONDBLCLK:
410             /*
411              * If the double click was within m_dBorder of an
412              * edge, send the HWN_BORDERDOUBLECLICKED notification.
413              *
414              * Because we're always sized just larger than our child
415              * window by the border width, we can only *get* this
416              * message when the mouse is on the border.  So we can
417              * just send the notification.
418              */
419             if (nullptr!=phw->m_hWndAssociate)
420             {
421                 SendMessageW(
422                     phw->m_hWndAssociate, WM_COMMAND,
423                     MAKEWPARAM(phw->m_uID, HWN_BORDERDOUBLECLICKED),
424                     reinterpret_cast<LPARAM>(hWnd));
425             }
426 
427             break;
428         default:
429             return DefWindowProcW(hWnd, iMsg, wParam, lParam);
430     }
431 
432     return 0;
433 }
434 
435 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
436