4 * ---------------------------------------------------------------------------
6 * Implementation of a minimal C++ class framework for use with the
7 * Microsoft Windows Application Programming Interface.
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:--
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
19 * to obtain the implementations of the SashWindowMaker abstract base class,
20 * together with its HorizontalSashWindowMaker and VerticalSashWindowMaker
21 * derived classes, respectively.
23 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
24 * Copyright (C) 2012, 2015, MinGW.org Project.
26 * ---------------------------------------------------------------------------
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:
35 * The above copyright notice, this permission notice, and the following
36 * disclaimer shall be included in all copies or substantial portions of
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.
47 * ---------------------------------------------------------------------------
50 #define WIN32_LEAN_AND_MEAN
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
60 #undef CORE_IMPLEMENTATION
64 #ifdef HSASH_IMPLEMENTATION
65 /* ...when the horizontal sash case IS selected, we ensure that
66 * the vertical sash case ISN'T...
68 # undef VSASH_IMPLEMENTATION
70 /* ...otherwise, when the horizontal sash case ISN'T selected...
72 #elif !defined VSASH_IMPLEMENTATION
73 /* ...and the vertical sash case ISN'T either, then we reselect
76 # define CORE_IMPLEMENTATION
81 # ifdef CORE_IMPLEMENTATION
82 /* Neither the HSASH_IMPLEMENTATION nor the VSASH_IMPLEMENTATION
83 * was selected; implement the SashWindowMaker class.
85 SashWindowMaker::SashWindowMaker
86 ( HINSTANCE app, double minval, double initval, double maxval ):
87 ChildWindowMaker( app ), MinRangeFactor( minval ), MaxRangeFactor( maxval ),
88 DisplacementFactor( initval ){ ValidateDisplacementFactor(); }
90 void SashWindowMaker::RegisterWindowClassName( const char *ClassName )
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.
96 WindowClassMaker WindowClassRegistry( AppInstance );
97 WindowClassRegistry.SetCursor( LoadCursor( NULL, CursorStyle() ));
98 WindowClassRegistry.Register( ClassName );
101 long SashWindowMaker::OnLeftButtonDown( void )
103 /* Capture the mouse over a sash bar, and initiate the drag
104 * operation to resize the adjacent sash panes.
107 SetCapture( AppWindow );
109 /* Establish the viewport region of the owner window, within
110 * which the sash panes are defined.
112 GetClientRect( (owner = GetParent( AppWindow )), &frame );
113 long width = GetFrameWidth(), height = GetFrameHeight();
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.
120 GetWindowRect( owner, &frame );
121 long border = (GetFrameWidth() - width) / 2;
122 SetClippingRegion( width, height, border );
123 ClipCursor( &frame );
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.
131 GetWindowRect( owner, &frame );
132 frame.top = frame.bottom - border - height;
133 frame.left += border;
137 long SashWindowMaker::OnMouseMove( WPARAM flags )
139 /* When the mouse has been captured over a sash bar...
141 if( flags & MK_LBUTTON )
143 /* ...compute the position to which it has been dragged,
144 * ensuring that it remains within the permitted bounds...
146 SetDisplacementFactor( GetMessagePos() );
147 ValidateDisplacementFactor();
149 /* ...then dynamically update the owner window display,
150 * to reflect the sash movement.
152 WindowObjectReference( GetParent( AppWindow ))->AdjustLayout();
157 void SashWindowMaker::ValidateDisplacementFactor()
159 /* Helper routine to ensure that sash bar movement
160 * remains within permitted bounds.
162 if( DisplacementFactor < MinRangeFactor )
163 DisplacementFactor = MinRangeFactor;
164 else if( DisplacementFactor > MaxRangeFactor )
165 DisplacementFactor = MaxRangeFactor;
168 long SashWindowMaker::OnLeftButtonUp( void )
170 /* Complete a drag operation on a sash bar; first we
171 * release the mouse from the clipping region...
176 /* ...then perform a final update of the owner window,
177 * to clean up any display artefacts which may have been
178 * left behind by dragging the sash bar...
180 HWND owner = GetParent( AppWindow );
181 InvalidateRect( owner, NULL, TRUE );
182 UpdateWindow( owner );
184 /* ...and we are done.
190 /* When compiling each of the HSASH_IMPLEMENTATION module, and
191 * the VSASH_IMPLEMENTATION module...
193 class MousePositionMapper
195 /* This locally declared, all-inline class is used to facilitate
196 * identification of the co-ordinates of the mouse position.
199 union { unsigned long v; struct { unsigned short x, y; }; } pos;
202 MousePositionMapper( unsigned long v ){ pos.v = v; }
203 long X(){ return pos.x; }
204 long Y(){ return pos.y; }
208 #ifdef HSASH_IMPLEMENTATION
209 /* This is the case where we are compiling the implementation for
210 * the HorizontalSashWindowMaker class.
212 const char *HorizontalSashWindowMaker::ClassName = NULL;
213 const char *HorizontalSashWindowMaker::RegisteredClassName( void )
215 /* Helper routine to ensure that the appropriate window class
216 * name is registered on first instantiation of any class object.
218 if( ClassName == NULL )
219 RegisterWindowClassName( ClassName = "HSashCtrl" );
223 void HorizontalSashWindowMaker::
224 SetClippingRegion( long width, long height, long border )
226 /* Helper routine, called by the OnLeftButtonDown() method which is
227 * inherited from the SashWindowMaker base class, to establish left
228 * and right movement bounds for the sash bar, within the frame of
231 ScaleFactor = (double)(width);
232 frame.right -= border + (long)( (1.0 - MaxRangeFactor) * ScaleFactor );
233 frame.left += border + (long)( MinRangeFactor * ScaleFactor );
236 void HorizontalSashWindowMaker::SetDisplacementFactor( unsigned long pos )
238 /* Helper routine, called by the OnMouseMove() method which is
239 * inherited from the SashWindowMaker base class, to establish the
240 * offset of the sash bar from the left hand side of the owner
241 * window, as it is dragged by the mouse.
243 MousePositionMapper locate( pos );
244 DisplacementFactor = (double)(locate.X() - frame.left) / ScaleFactor;
247 # elif defined VSASH_IMPLEMENTATION
248 /* This is the case where we are compiling the implementation for
249 * the VerticalSashWindowMaker class.
251 const char *VerticalSashWindowMaker::ClassName = NULL;
252 const char *VerticalSashWindowMaker::RegisteredClassName( void )
254 /* Helper routine to ensure that the appropriate window class
255 * name is registered on first instantiation of any class object.
257 if( ClassName == NULL )
258 RegisterWindowClassName( ClassName = "VSashCtrl" );
262 void VerticalSashWindowMaker::
263 SetClippingRegion( long width, long height, long border )
265 /* Helper routine, called by the OnLeftButtonDown() method which is
266 * inherited from the SashWindowMaker base class, to establish upper
267 * and lower movement bounds for the sash bar, within the frame of
270 ScaleFactor = (double)(height); frame.bottom -= border;
271 frame.top = frame.bottom - (long)( (1.0 - MinRangeFactor) * ScaleFactor );
272 frame.bottom -= (long)( (1.0 - MaxRangeFactor) * ScaleFactor );
275 void VerticalSashWindowMaker::SetDisplacementFactor( unsigned long pos )
277 /* Helper routine, called by the OnMouseMove() method which is
278 * inherited from the SashWindowMaker base class, to establish the
279 * offset of the sash bar from the top edge of the owner window,
280 * as it is dragged by the mouse.
282 MousePositionMapper locate( pos );
283 DisplacementFactor = (double)(locate.Y() - frame.top) / ScaleFactor;
289 /* $RCSfile$: end of file */