1 /* $Id: resize.c,v 1.1 2005/05/15 09:06:04 admin Exp $ */
2 /*******************************************************************************
3 Copyright (c) 2004, Alexander R. Pruss
6 Redistribution and use in source and binary forms, with or without modification,
7 are permitted provided that the following conditions are met:
9 Redistributions of source code must retain the above copyright notice, this
10 list of conditions and the following disclaimer.
12 Redistributions in binary form must reproduce the above copyright notice, this
13 list of conditions and the following disclaimer in the documentation and/or
14 other materials provided with the distribution.
16 Neither the name of the PalmResize Project nor the names of its
17 contributors may be used to endorse or promote products derived from this
18 software without specific prior written permission.
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
24 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *******************************************************************************/
34 #include <PalmOSGlue.h>
37 #ifdef SUPPORT_DIA_HANDERA
42 #include "rsrc/rsrc.h"
44 static void DebugInfo(const char *format, ...)
50 len = snprintf(buf, sizeof(buf), "%lu ", TimGetTicks());
52 va_start(args, format);
53 vsnprintf(buf+len, sizeof(buf)-len, format, args);
56 ClipboardAppendItem(clipboardText, buf, StrLen(buf));
66 DIAFormEntryType* entry;
67 } ResizeTemporaryData;
70 static DIAFormEntryType* formList = NULL;
71 static DIAStateType* bins;
72 static UInt16 numBins;
73 static UInt16 formCount = 0;
74 static ResizeTemporaryData active;
75 static Boolean haveWinDisplayChangedEvent = false;
79 RESIZE_SECTION static UInt16 StandardExtent( void )
81 #ifdef SUPPORT_DIA_HANDERA
82 if ( GetDIAHardware() == DIA_HARDWARE_HANDERA )
91 /* Update form, but only once */
92 RESIZE_SECTION static void UniqueUpdateForm( UInt16 formID, UInt16 code )
95 MemSet( &e, sizeof(EventType), 0 );
96 e.eType = frmUpdateEvent;
97 e.data.frmUpdate.formID = formID;
98 e.data.frmUpdate.updateCode = code;
99 EvtAddUniqueEventToQueue( &e, 0, true );
100 DebugInfo("Queuing frmUpdateForm");
105 /* Same as FrmGetObjectIndex() but works with GSI_OBJECT_ID, too */
106 RESIZE_SECTION static UInt16 MyFrmGetObjectIndex( FormPtr formPtr, UInt16 id )
109 if ( id != GSI_OBJECT_ID )
110 return FrmGetObjectIndex( formPtr, id );
111 for ( i = FrmGetNumberOfObjects( formPtr ) - 1 ; 0 < i ; i -- ) {
112 if ( FrmGetObjectType( formPtr, i ) == frmGraffitiStateObj ) {
121 RESIZE_SECTION static void WinGlueGetBounds( WinHandle winH, RectangleType* rect )
125 err = FtrGet( sysFtrCreator, sysFtrNumROMVersion, &version );
126 if ( err == errNone && 0x04003000 <= version ) {
127 WinGetBounds( winH, rect );
131 oldH = WinSetDrawWindow( winH );
132 WinGetDrawWindowBounds( rect );
133 WinSetDrawWindow( oldH );
139 RESIZE_SECTION static void SafeFrmGetObjectBounds
141 const FormType* formPtr,
148 oldWin = WinSetDrawWindow( FrmGetWindowHandle( formPtr ) );
150 FrmGetObjectBounds( formPtr, objectIndex, rect );
152 if ( NULL != oldWin )
153 WinSetDrawWindow( oldWin );
158 RESIZE_SECTION static void SafeFrmSetObjectBounds
167 oldWin = WinSetDrawWindow( FrmGetWindowHandle( formPtr ) );
169 FrmSetObjectBounds( formPtr, objectIndex, rect );
171 if ( NULL != oldWin )
172 WinSetDrawWindow( oldWin );
177 RESIZE_SECTION static void AddForm( UInt16 indexInList, MemHandle handle, UInt16 formID )
180 DIAConfigType* config;
182 formList[ indexInList ].configHandle = handle;
183 if ( handle == NULL ) {
187 config = ( DIAConfigType* )MemHandleLock( handle );
188 numObjects = ( ( config->sizeInWords + 1 ) * sizeof( UInt16 ) -
189 sizeof( DIAConfigType ) ) /
190 sizeof( DIAConfigEntryType );
192 formList[ indexInList ].formID = formID;
193 formList[ indexInList ].config = config;
194 formList[ indexInList ].numObjects = numObjects;
195 formList[ indexInList ].open = false;
196 formList[ indexInList ].callback = NULL;
198 if ( config->flags & DIA_FORM_USE_BIN &&
199 numBins < 1 + config->bin )
200 numBins = 1 + config->bin;
205 /* This sets up the original bounds array as needed */
206 RESIZE_SECTION static void InitialSetupForm( UInt16 indexInList )
208 RectangleType* originalBounds;
213 numObjects = formList[ indexInList ].numObjects;
214 if ( numObjects == 0 )
216 if ( formList[ indexInList ].originalBounds != NULL )
218 formPtr = FrmGetFormPtr( formList[ indexInList ].formID );
219 if ( formPtr == NULL )
222 originalBounds = ( RectangleType* )SafeMemPtrNew( numObjects *
223 sizeof( RectangleType ) );
224 formList[ indexInList ].originalBounds = originalBounds;
226 /* First object is the form itself */
227 WinGlueGetBounds( FrmGetWindowHandle( formPtr ), &( originalBounds[ 0 ] ) );
229 /* Now on to the other objects */
230 for ( i = 1 ; i < numObjects ; i++ ) {
232 objectIndex = MyFrmGetObjectIndex( formPtr,
233 formList[ indexInList ].config->objectList[ i ].objectID );
234 SafeFrmGetObjectBounds( formPtr, objectIndex, &( originalBounds[ i ] ) );
240 /* Adjust one coordinate */
241 RESIZE_SECTION static Coord Adjust
243 Coord value, /* old value to adjust */
244 Coord oldObjectExtent, /* old extent if relevant */
245 Coord newObjectExtent, /* already adjusted extent if relevant */
246 Coord oldExtent, /* old form/screen extent */
247 Coord newExtent, /* new form/screen extent */
248 UInt16 shiftedFlag /* adjustment flag, shifted down as needed */
253 delta = newExtent - oldExtent;
255 switch ( shiftedFlag ) {
256 case DIA_X_FIX >> DIA_SHIFT_X:
258 case DIA_X_RATIO >> DIA_SHIFT_X:
259 return value * ( Int32 )newExtent / oldExtent;
260 case DIA_X_RIGHT >> DIA_SHIFT_X:
261 return newExtent - ( oldExtent - value - oldObjectExtent ) - newObjectExtent;
262 case DIA_X_PLUS_DW >> DIA_SHIFT_X:
263 return value + delta;
264 case DIA_X_PLUS_1_2_DW >> DIA_SHIFT_X:
265 return value + delta / 2;
266 case DIA_X_PLUS_1_3_DW >> DIA_SHIFT_X:
267 return value + delta / 3;
268 case DIA_X_PLUS_2_3_DW >> DIA_SHIFT_X:
269 return value + 2 * delta / 3;
270 case DIA_X_PLUS_1_4_DW >> DIA_SHIFT_X:
271 return value + delta / 4;
272 case DIA_X_PLUS_3_4_DW >> DIA_SHIFT_X:
273 return value + 3 * delta / 4;
274 default: /* should not happen */
281 /* Get new bounds for an object, adjusted for DIA */
282 RESIZE_SECTION static void GetNewBounds( UInt16 displayExtentX, UInt16 displayExtentY,
283 UInt16 stdFormExtentX, UInt16 stdFormExtentY,
284 RectangleType* oldBounds, RectangleType* newBounds,
285 DIAConfigEntryType* configEntry )
288 flags = configEntry->flags;
290 if ( flags & DIA_MASK_W ) {
291 newBounds->extent.x = Adjust( oldBounds->extent.x, 0, 0,
294 ( flags & DIA_MASK_W ) >> DIA_SHIFT_W );
296 if ( flags & DIA_MASK_H ) {
297 newBounds->extent.y = Adjust( oldBounds->extent.y, 0, 0,
300 ( flags & DIA_MASK_H ) >> DIA_SHIFT_H );
302 newBounds->topLeft.x = Adjust( oldBounds->topLeft.x, oldBounds->extent.x,
304 stdFormExtentX, displayExtentX,
305 ( flags & DIA_MASK_X ) >> DIA_SHIFT_X );
306 newBounds->topLeft.y = Adjust( oldBounds->topLeft.y, oldBounds->extent.y,
308 stdFormExtentY, displayExtentY,
309 ( flags & DIA_MASK_Y ) >> DIA_SHIFT_Y );
314 /* This compares two rectangles. If sonyDoubleSecond is set and the first
315 bounds are exactly double the size of the first and DIA hardware is
316 DIA_HARDWARE_SONY1, then they also match. */
317 RESIZE_SECTION static Boolean SameBounds( RectangleType* a, RectangleType* b,
318 Boolean sonyDoubleSecond )
321 compare = ( a->extent.y == b->extent.y && a->extent.x == b->extent.x &&
322 a->topLeft.y == b->topLeft.y && a->topLeft.x == b->topLeft.x );
323 #ifdef SUPPORT_DIA_SONY
324 if ( ! compare && GetDIAHardware() == DIA_HARDWARE_SONY1 ) {
325 return a->extent.y == 2 * b->extent.y &&
326 a->extent.x == 2 * b->extent.x &&
327 a->topLeft.y == 2 * b->topLeft.y &&
328 a->topLeft.x == 2 * b->topLeft.x;
336 /* Returns true if there is moving done */
337 RESIZE_SECTION static Boolean MoveObjectsInForm( UInt16 indexInList )
344 DIAFormEntryType* entry;
347 RectangleType newBounds;
348 RectangleType curBounds;
350 entry = &( formList[ indexInList ] );
352 formPtr = FrmGetFormPtr( entry->formID );
353 if ( formPtr == NULL )
355 InitialSetupForm( indexInList );
356 WinGetDisplayExtent( &extentX, &extentY );
358 /* First object is the form itself */
359 WinGlueGetBounds( FrmGetWindowHandle( formPtr ), &curBounds );
360 newBounds = curBounds;
361 GetNewBounds( extentX, extentY, StandardExtent(), StandardExtent(),
362 &( formList[ indexInList ].originalBounds[ 0 ] ),
363 &newBounds, &( entry->config->objectList[ 0 ] ) );
365 /* { Char ss[55]; StrPrintF(ss, " %d x %d ", extentX, extentY ); DebugInfo(ss); DebugInfo("abc"); } DebugInfo("def"); */
367 if ( ( SameBounds( &curBounds, &newBounds, true ) ||
368 ( formList[ indexInList ].open &&
369 SameBounds( &newBounds, &( formList[ indexInList ].lastBounds ), false ) ) ) &&
370 extentX == entry->lastExtentX && extentY == entry->lastExtentY ) {
371 DebugInfo( "skipping resize" );
375 dw = newBounds.extent.x - curBounds.extent.x;
376 dh = newBounds.extent.y - curBounds.extent.y;
378 if ( GetDIAHardware() == DIA_HARDWARE_SONY1 ||
379 GetDIAHardware() == DIA_HARDWARE_HANDERA ) {
380 /* Sony OS4 and Handera work differently from everybody else */
381 FrmEraseForm( formPtr );
384 entry->lastBounds = newBounds;
385 entry->lastExtentX = extentX;
386 entry->lastExtentY = extentY;
387 WinSetBounds( FrmGetWindowHandle(formPtr), &newBounds );
389 /* The rest is resized relative to the form itself */
390 extentX = newBounds.extent.x;
391 extentY = newBounds.extent.y;
392 focus = FrmGetFocus( formPtr );
394 for ( i = 1 ; i < entry->numObjects ; i++ ) {
397 objectIndex = MyFrmGetObjectIndex( formPtr,
398 entry->config->objectList[ i ].objectID );
399 SafeFrmGetObjectBounds( formPtr, objectIndex, &curBounds );
400 newBounds = curBounds;
401 GetNewBounds( extentX, extentY,
402 entry->originalBounds[ 0 ].extent.x,
403 entry->originalBounds[ 0 ].extent.y,
404 &( entry->originalBounds[ i ] ),
405 &newBounds, &( entry->config->objectList[ i ] ) );
407 if ( ! SameBounds( &curBounds, &newBounds, false ) ) {
408 SafeFrmSetObjectBounds( formPtr, objectIndex, &newBounds );
410 switch ( FrmGetObjectType( formPtr, objectIndex ) ) {
412 /* case frmScrollBarObj: */
417 field = ( FieldType* ) FrmGetObjectPtr( formPtr, objectIndex );
419 if ( entry->config->objectList[ i ].flags & DIA_H_GRANULAR ) {
423 oldFont = FntSetFont( FldGetFont( field ) );
425 newHeight = newBounds.extent.y / FntLineHeight() *
428 FntSetFont( oldFont );
430 if ( 0 < newHeight ) {
431 newBounds.extent.y = newHeight;
432 SafeFrmSetObjectBounds( formPtr, objectIndex, &newBounds );
435 insPt = FldGetInsPtPosition( field );
436 FldRecalculateField( field, true );
437 FldSetInsPtPosition( field, insPt );
438 FldSendChangeNotification( field );
442 if ( entry->config->objectList[ i ].flags & DIA_H_GRANULAR ) {
447 list = ( ListType* ) FrmGetObjectPtr( formPtr, objectIndex );
449 oldFont = FntSetFont( LstGlueGetFont( list ) );
451 newHeight = newBounds.extent.y / FntLineHeight() *
454 FntSetFont( oldFont );
456 if ( 0 < newHeight ) {
457 newBounds.extent.y = newHeight;
458 SafeFrmSetObjectBounds( formPtr, objectIndex, &newBounds );
469 if ( formList[ indexInList ].callback ) {
470 (*formList[ indexInList ].callback)(formPtr, dw, dh);
473 if ( FrmGetFocus( formPtr ) != focus )
474 FrmSetFocus( formPtr, focus );
481 void InitializeResizeSupport( UInt16 formMapId )
483 MemHandle indexHandle;
487 if ( formList != NULL ) {
490 indexHandle = DmGetResource( WORD_LIST_TYPE, formMapId );
491 if ( indexHandle == NULL ) {
495 if ( DIA_HARDWARE_NONE == InitializeDIA() ) {
499 index = ( DIAIndexType* )MemHandleLock( indexHandle );
501 formCount = index->count * sizeof( UInt16 ) /
502 sizeof( DIAIndexEntryType );
504 if ( formCount == 0 ) {
509 formList = ( DIAFormEntryType* ) SafeMemPtrNew( formCount *
510 sizeof( DIAFormEntryType ) );
511 MemSet( formList, formCount * sizeof( DIAFormEntryType ), 0 );
513 for ( i = 0 ; i < formCount ; i++ ) {
514 AddForm( i, DmGetResource( WORD_LIST_TYPE, index->mapList[ i ].to ),
515 index->mapList[ i ].from );
518 MemHandleUnlock( indexHandle );
519 DmReleaseResource( indexHandle );
522 bins = ( DIAStateType* ) SafeMemPtrNew( numBins *
523 sizeof( DIAStateType ) );
524 for ( i = 0 ; i < numBins ; i++ )
525 bins[ i ] = DIA_STATE_UNDEFINED;
532 void TerminateResizeSupport( void )
536 if ( formList == NULL )
539 for ( i = 0 ; i < formCount ; i++ ) {
540 if ( NULL != formList[ i ].configHandle ) {
541 MemHandleUnlock( formList[ i ].configHandle );
542 DmReleaseResource( formList[ i ].configHandle );
543 if ( formList[ i ].originalBounds != NULL )
544 SafeMemPtrFree( formList[ i ].originalBounds );
547 SafeMemPtrFree( formList );
550 SafeMemPtrFree( bins );
557 void LoadResizePrefs( UInt32 appID, UInt16 prefID )
563 if ( formList == NULL || numBins == 0 ||
565 PrefGetAppPreferences( appID, prefID, NULL, &size, true ) ) {
569 if ( numBins * sizeof( DIAStateType ) < size ) {
570 size = numBins * sizeof( DIAStateType );
573 PrefGetAppPreferences( appID, prefID, bins, &size, true );
578 void SaveResizePrefs( UInt32 appID, UInt16 prefID, Int16 version )
580 if ( formList == NULL || numBins == 0 )
583 PrefSetAppPreferences( appID, prefID, version, bins,
584 numBins * sizeof( DIAStateType ), true );
589 RESIZE_SECTION static UInt16 GetFormIndex( UInt16 formID )
593 if ( formList == NULL )
596 for ( i = 0 ; i < formCount ; i++ )
597 if ( formList[ i ].formID == formID )
605 void SetResizePolicy( UInt16 formID )
607 if ( GetFormIndex( formID ) < formCount ) {
608 SetCustomDIAPolicy( formID );
613 void SetResizeCallback( UInt16 formID, DIAResizeCallback fn )
616 i = GetFormIndex( formID );
617 if ( i < formCount ) {
618 formList[ i ].callback = fn;
624 RESIZE_SECTION static Boolean GetFormInfo( void )
626 active.formID = FrmGetActiveFormID();
627 active.formPtr = FrmGetActiveForm();
628 active.index = GetFormIndex( active.formID );
630 if ( active.index < formCount ) {
631 active.entry = &( formList[ active.index ] );
632 active.flags = active.entry->config->flags;
644 RESIZE_SECTION static Boolean PrepareForm( void )
646 if ( active.index == formCount ) {
647 SetDIAState( DIA_STATE_MAX );
648 SetDIAAllowResize( false );
652 return MoveObjectsInForm( active.index );
657 RESIZE_SECTION static void SaveDIAState( void )
659 if ( active.index == formCount )
662 if ( active.entry->config->flags & DIA_FORM_USE_BIN ) {
663 bins[ active.entry->config->bin ] = GetDIAState();
670 RESIZE_SECTION static Boolean FormStartup( void )
672 DIAStateType newState;
678 if ( active.index == formCount ) {
679 SetDIAState( DIA_STATE_MAX );
680 SetDIAAllowResize( false );
681 SetDIAConstraints( FrmGetWindowHandle( active.formPtr ), false, false );
685 newState = GetDIAState();
687 if ( ( active.flags & DIA_FORM_USE_BIN ) &&
688 ( bins[ active.entry->config->bin ] != DIA_STATE_UNDEFINED ) ) {
689 newState = bins[ active.entry->config->bin ];
690 /* if ( newState == DIA_STATE_MIN ) DebugInfo("bin = min");
691 if ( newState == DIA_STATE_MAX ) DebugInfo("bin = max"); */
693 else if ( ! ( active.flags & DIA_FORM_KEEP_LAST ) ) {
694 newState = active.entry->config->preferredState;
697 if ( active.flags & DIA_FORM_NO_RESIZE ) {
706 big = ( newState == DIA_STATE_MIN || newState == DIA_STATE_NO_STATUS_BAR );
707 allowBig = allowBig || big;
709 SetDIAConstraints( FrmGetWindowHandle( active.formPtr ), allowBig, allowBig );
711 SetDIAState( newState );
713 SetDIAAllowResize( allowResize );
715 changed = PrepareForm();
717 /* if ( changed ) DebugInfo("Changed in FormStartup"); */
725 RESIZE_SECTION static void ForceRedrawAll( void )
728 for ( i = 0 ; i < formCount ; i++ ) {
729 if ( formList[ i ].open )
730 formList[ i ].forceRedraw = true;
736 Boolean ResizeHandleFrmOpenEvent( void )
739 #ifdef SUPPORT_DIA_HANDERA
740 if ( GetDIAHardware() == DIA_HARDWARE_HANDERA &&
741 ( active.index == formCount || ! ( active.flags & DIA_FORM_HANDERA ) )
743 VgaFormModify( active.formPtr, vgaFormModify160To240 );
746 if ( active.index < formCount ) {
747 MemSet( &( active.entry->lastBounds ), sizeof( RectangleType ), 0 );
748 active.entry->lastExtentX = -1;
749 active.entry->lastExtentY = -1;
750 active.entry->forceRedraw = false;
752 DebugInfo("FrmOpen");
753 PushCoordinateSystemToStandard();
755 if ( active.index < formCount ) {
756 active.entry->open = true;
758 PopCoordinateSystem();
759 haveWinDisplayChangedEvent = false;
765 Boolean ResizeHandleFrmCloseEvent( void )
767 if ( GetFormInfo() ) {
768 DebugInfo("FrmClose");
769 active.entry->open = false;
770 active.entry->forceRedraw = false;
778 Boolean ResizeHandleWinDisplayChangedEvent( void )
780 haveWinDisplayChangedEvent = false;
781 if ( ! GetFormInfo() )
784 PushCoordinateSystemToStandard();
786 DebugInfo("WinDisplayChanged");
787 if ( PrepareForm() || active.entry->forceRedraw ) {
788 UniqueUpdateForm( active.formID, frmRedrawUpdateCode );
789 active.entry->forceRedraw = false;
793 PopCoordinateSystem();
800 Boolean ResizeHandleWinExitEvent( void )
802 DebugInfo("WinExit");
809 Boolean ResizeHandleFrmRedrawUpdateCode( void )
812 DebugInfo("FrmUpdate");
813 if ( active.index < formCount )
814 active.entry->forceRedraw = false;
820 Boolean ResizeHandleWinEnterEvent( void )
823 DebugInfo("WinEnter");
824 if ( active.index == formCount ) {
828 PushCoordinateSystemToStandard();
830 /* If the last form we have record of being in is this one, then
831 we may have missed what happened on a form. */
833 if ( active.entry->open && ( FormStartup() ||
834 active.entry->forceRedraw ) )
837 DebugInfo("WinEnter: Possibly missed winDisplayChangedEvent");
838 MemSet( &e, sizeof( EventType ), 0 );
839 e.eType = winDisplayChangedEvent;
840 EvtAddUniqueEventToQueue( &e, 0, true );
841 DebugInfo("Queuing display change");
842 active.entry->forceRedraw = true;
845 PopCoordinateSystem();
853 void SetHaveWinDisplayChangedEvent( Boolean value )
855 DebugInfo("SetHaveWinDisplayChangedEvent()");
856 haveWinDisplayChangedEvent = value;
863 void ResizeRefreshCurrentForm( void )
866 if ( active.index == formCount )
869 PushCoordinateSystemToStandard();
873 UniqueUpdateForm( active.formID, frmRedrawUpdateCode );
875 PopCoordinateSystem();
881 Boolean ResizeHandleEvent( EventType* event )
883 Boolean handled = false;
884 ResizeTemporaryData old;
886 switch ( event->eType ) {
891 ResizeHandleFrmOpenEvent();
895 case frmCloseEvent: {
897 ResizeHandleFrmCloseEvent();
901 case winEnterEvent: {
903 ResizeHandleWinEnterEvent();
909 ResizeHandleWinExitEvent();
913 case winDisplayChangedEvent: {
915 ResizeHandleWinDisplayChangedEvent();
920 if ( event->data.frmUpdate.updateCode == frmRedrawUpdateCode ) {
922 ResizeHandleFrmRedrawUpdateCode();