OSDN Git Service

wtklite version 0.1.2 released.
[mingw/wtklite.git] / sashctrl.cpp
1 /*
2  * sashctrl.cpp
3  *
4  * ---------------------------------------------------------------------------
5  *
6  * Implementation of a minimal C++ class framework for use with the
7  * Microsoft Windows Application Programming Interface.
8  *
9  * $Id$
10  *
11  * This file provides the implementation for each of the three C++ classes
12  * which are required to implement sash window controls.  It must be compiled
13  * to generate three separate object modules:--
14  *
15  *   c++ -c sashctrl.cpp -o sashctrl.o
16  *   c++ -D HSASH_IMPLEMENTATION -c sashctrl.cpp -o hsashctl.o
17  *   c++ -D VSASH_IMPLEMENTATION -c sashctrl.cpp -o vsashctl.o
18  *
19  * to obtain the implementations of the SashWindowMaker abstract base class,
20  * together with its HorizontalSashWindowMaker and VerticalSashWindowMaker
21  * derived classes, respectively.
22  *
23  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
24  * Copyright (C) 2012, MinGW.org Project.
25  *
26  * ---------------------------------------------------------------------------
27  *
28  * Permission is hereby granted, free of charge, to any person obtaining a
29  * copy of this software and associated documentation files (the "Software"),
30  * to deal in the Software without restriction, including without limitation
31  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
32  * and/or sell copies of the Software, and to permit persons to whom the
33  * Software is furnished to do so, subject to the following conditions:
34  *
35  * The above copyright notice, this permission notice, and the following
36  * disclaimer shall be included in all copies or substantial portions of
37  * the Software.
38  *
39  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
40  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
42  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
44  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
45  * DEALINGS IN THE SOFTWARE.
46  *
47  * ---------------------------------------------------------------------------
48  *
49  */
50 #define  WIN32_LEAN_AND_MEAN
51
52 #include "wtklite.h"
53
54 /* Identify the class implementation to be compiled; each of
55  * the HSASH_IMPLEMENTATION and VSASH_IMPLEMENTATION must be
56  * explicitly requested.  Initially, we assume that either of
57  * these may have been specified, so we deselect the fallback
58  * case...
59  */
60 #undef CORE_IMPLEMENTATION
61
62 /* ...then...
63  */
64 #ifdef HSASH_IMPLEMENTATION
65  /* ...when the horizontal sash case IS selected, we ensure that
66   * the vertical sash case ISN'T...
67   */
68 # undef  VSASH_IMPLEMENTATION
69
70 /* ...otherwise, when the horizontal sash case ISN'T selected...
71  */
72 #elif !defined VSASH_IMPLEMENTATION
73  /* ...and the vertical sash case ISN'T either, then we reselect
74   * the fallback case.
75   */
76 # define CORE_IMPLEMENTATION
77 #endif
78
79 namespace WTK
80 {
81 # ifdef CORE_IMPLEMENTATION
82   /* Neither the HSASH_IMPLEMENTATION nor the VSASH_IMPLEMENTATION
83    * was selected; implement the SashWindowMaker class.
84    */
85   SashWindowMaker::SashWindowMaker
86   ( HINSTANCE app, double minval, double initval, double maxval ):
87     ChildWindowMaker( app ), MinRangeFactor( minval ), MaxRangeFactor( maxval ),
88     DisplacementFactor( initval ){ ValidateDisplacementFactor(); }
89
90   void SashWindowMaker::RegisterWindowClassName( const char *ClassName )
91   {
92     /* Helper routine, to ensure that an appropriate window class name
93      * is registered, as required for instantiation of any object of the
94      * derived HorizontalSashWindowMaker or VerticalSashWindowMaker class.
95      */
96     WindowClassMaker WindowClassRegistry( AppInstance );
97     WindowClassRegistry.SetCursor( LoadCursor( NULL, CursorStyle() ));
98     WindowClassRegistry.Register( ClassName );
99   }
100
101   long SashWindowMaker::OnLeftButtonDown( void )
102   {
103     /* Capture the mouse over a sash bar, and initiate the drag
104      * operation to resize the adjacent sash panes.
105      */
106     HWND owner;
107     SetCapture( AppWindow );
108
109     /* Establish the viewport region of the owner window, within
110      * which the sash panes are defined.
111      */
112     GetClientRect( (owner = GetParent( AppWindow )), &frame );
113     long width = GetFrameWidth(), height = GetFrameHeight();
114
115     /* Adjust the frame bounds to accommodate the entire extent
116      * of the owner window, then relative to those, establish the
117      * clipping region within which mouse movement is to be confined
118      * while dragging the sash bar.
119      */
120     GetWindowRect( owner, &frame );
121     long border = (GetFrameWidth() - width) / 2;
122     SetClippingRegion( width, height, border );
123     ClipCursor( &frame );
124
125     /* Readjust the frame bounds to the entire extent of the owner
126      * window, (they will have been modified while setting up the
127      * clipping region), then further adjust the top edge and left
128      * side entries, to reflect the offset of the viewport within
129      * the overall window bounds.
130      */
131     GetWindowRect( owner, &frame );
132     frame.top = frame.bottom - border - height;
133     frame.left += border;
134     return EXIT_SUCCESS;
135   }
136
137   long SashWindowMaker::OnMouseMove( WPARAM flags )
138   {
139     /* When the mouse has been captured over a sash bar...
140      */
141     if( flags & MK_LBUTTON )
142     {
143       /* ...compute the position to which it has been dragged,
144        * ensuring that it remains within the permitted bounds...
145        */
146       SetDisplacementFactor( GetMessagePos() );
147       ValidateDisplacementFactor();
148
149       /* ...then dynamically update the owner window display,
150        * to reflect the sash movement.
151        */
152       WindowObjectReference( GetParent( AppWindow ))->AdjustLayout();
153     }
154   }
155
156   void SashWindowMaker::ValidateDisplacementFactor()
157   {
158     /* Helper routine to ensure that sash bar movement
159      * remains within permitted bounds.
160      */
161     if( DisplacementFactor < MinRangeFactor )
162       DisplacementFactor = MinRangeFactor;
163     else if( DisplacementFactor > MaxRangeFactor )
164       DisplacementFactor = MaxRangeFactor;
165   }
166
167   long SashWindowMaker::OnLeftButtonUp( void )
168   {
169     /* Complete a drag operation on a sash bar; first we
170      * release the mouse from the clipping region...
171      */
172     ReleaseCapture();
173     ClipCursor( NULL );
174
175     /* ...then perform a final update of the owner window,
176      * to clean up any display artefacts which may have been
177      * left behind by dragging the sash bar...
178      */
179     HWND owner = GetParent( AppWindow );
180     InvalidateRect( owner, NULL, TRUE );
181     UpdateWindow( owner );
182
183     /* ...and we are done.
184      */
185     return EXIT_SUCCESS;
186   }
187
188 #else
189   /* When compiling each of the HSASH_IMPLEMENTATION module, and
190    * the VSASH_IMPLEMENTATION module...
191    */
192   class MousePositionMapper
193   {
194     /* This locally declared, all-inline class is used to facilitate 
195      * identification of the co-ordinates of the mouse position.
196      */
197     private:
198       union { unsigned long v; struct { unsigned short x, y; }; } pos;
199
200     public:
201       MousePositionMapper( unsigned long v ){ pos.v = v; }
202       long X(){ return pos.x; }
203       long Y(){ return pos.y; }
204   };
205
206 #endif
207 #ifdef HSASH_IMPLEMENTATION
208   /* This is the case where we are compiling the implementation for
209    * the HorizontalSashWindowMaker class.
210    */
211   const char *HorizontalSashWindowMaker::ClassName = NULL;
212   const char *HorizontalSashWindowMaker::RegisteredClassName( void )
213   {
214     /* Helper routine to ensure that the appropriate window class
215      * name is registered on first instantiation of any class object.
216      */
217     if( ClassName == NULL )
218       RegisterWindowClassName( ClassName = "HSashCtrl" );
219     return ClassName;
220   }
221
222   void HorizontalSashWindowMaker::
223   SetClippingRegion( long width, long height, long border )
224   {
225     /* Helper routine, called by the OnLeftButtonDown() method which is
226      * inherited from the SashWindowMaker base class, to establish left
227      * and right movement bounds for the sash bar, within the frame of
228      * the owner window.
229      */
230     ScaleFactor = (double)(width);
231     frame.right -= border + (long)( (1.0 - MaxRangeFactor) * ScaleFactor );
232     frame.left += border + (long)( MinRangeFactor * ScaleFactor );
233   }
234
235   void HorizontalSashWindowMaker::SetDisplacementFactor( unsigned long pos )
236   {
237     /* Helper routine, called by the OnMouseMove() method which is
238      * inherited from the SashWindowMaker base class, to establish the
239      * offset of the sash bar from the left hand side of the owner
240      * window, as it is dragged by the mouse.
241      */
242     MousePositionMapper locate( pos );
243     DisplacementFactor = (double)(locate.X() - frame.left) / ScaleFactor;
244   }
245
246 # elif defined VSASH_IMPLEMENTATION
247   /* This is the case where we are compiling the implementation for
248    * the VerticalSashWindowMaker class.
249    */
250   const char *VerticalSashWindowMaker::ClassName = NULL;
251   const char *VerticalSashWindowMaker::RegisteredClassName( void )
252   {
253     /* Helper routine to ensure that the appropriate window class
254      * name is registered on first instantiation of any class object.
255      */
256     if( ClassName == NULL )
257       RegisterWindowClassName( ClassName = "VSashCtrl" );
258     return ClassName;
259   }
260
261   void VerticalSashWindowMaker::
262   SetClippingRegion( long width, long height, long border )
263   {
264     /* Helper routine, called by the OnLeftButtonDown() method which is
265      * inherited from the SashWindowMaker base class, to establish upper
266      * and lower movement bounds for the sash bar, within the frame of
267      * the owner window.
268      */
269     ScaleFactor = (double)(height); frame.bottom -= border;
270     frame.top = frame.bottom - (long)( (1.0 - MinRangeFactor) * ScaleFactor );
271     frame.bottom -= (long)( (1.0 - MaxRangeFactor) * ScaleFactor );
272   }
273
274   void VerticalSashWindowMaker::SetDisplacementFactor( unsigned long pos )
275   {
276     /* Helper routine, called by the OnMouseMove() method which is
277      * inherited from the SashWindowMaker base class, to establish the
278      * offset of the sash bar from the top edge of the owner window,
279      * as it is dragged by the mouse.
280      */
281     MousePositionMapper locate( pos );
282     DisplacementFactor = (double)(locate.Y() - frame.top) / ScaleFactor;
283   }
284
285 # endif
286 }
287
288 /* $RCSfile$: end of file */