OSDN Git Service

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