Rev 15168 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Language for Statistical Data Analysis* File RWindows.c* Copyright (C) 1998-1999 Ross Ihaka* 2000-2001 Stefano M. Iacus the R core team** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*** This file is adapted from the public demos coming with the Waste library* distribution: WASTE Text Engine © 1993-2000 Marco Piovanelli.** This file was originally written by: Wing Kwong (Tiki), WAN 3/2/99* Updated to last version of WasteLib library: Stefano M. Iacus, 2001** Original file was:** WASTE Demo Project:* Dialog Utilities** Copyright © 1993-1998 Marco Piovanelli* All Rights Reserved** C port by John C. Daub*//*This file is based on the WASTE and WASTE demo, I had do somemodification to make it function as the way R want.In here, we willhandle most of the things related to Window, the other routine whichis related to Graphic Window may be appear in another file called"RGWindow".The R Program will create four different kinds of window in thismoment, they are Console, Edit, Help and Graphic Window.Console Window : It is a Edit Window with a lot offunctionality. You can only have one console window, when theConsole window closed, the application closed. You can't remain theapplication open without the console window. This is very important,cause there have a huge part of program is based on this assumption.Edit Window : A Sample Edit window, it based on the WASTE DEMO.Graphic Window : It is related to GRWindow files. It is used for drawing.Help Window : Exactly like Edit Window. except I disable some ofthe functions.Notes:In here, we need to pay attention how WASTE create a window. If youusing another methods to create another kind of window, you bettercreate another event handlers for those window. All the thing likewindowPtr, DocumentHandle and WE instance is highly related. If youusing some standard methods to create another kind of winodw. Theywill probably generate linking error when they handling the eventsimplement in here.*//* INCLUDE HEADER FILE */#ifndef __ALIASES__#include <Aliases.h>#endif#include <Controls.h>#ifndef __ERRORS__#include <Errors.h>#endif#ifndef __FIXMATH__#include <FixMath.h>#endif#ifndef __TOOLUTILS__#include <ToolUtils.h>#endif#ifndef __FILETYPESANDCREATORS__#include <FileTypesAndCreators.h>#endif/*#ifndef _LongCoords_#include "LongCoords.h"#endif*/#ifndef __WEDEMOAPP__#include "RIntf.h"#endif#ifndef __QUICKDRAW__#include <Quickdraw.h>#endif#ifndef __SMARTSCROLLAPI__#include "SmartScroll.h"#endif#include "WETabs.h"#include "WETabHooks.h"#ifdef HAVE_CONFIG_H#include <config.h>#endif#include "Defn.h"#include "Graphics.h"#include <Rdevices.h>#include <R_ext/Boolean.h>/* Define Constant */#define eGWin 11extern Str255 PostFont, UserFont;extern char *mac_getenv(const char *name);extern SInt32 systemVersion ;void UniqueWinTitle(void);void RemWinMenuItem(void);/* Constant, Global variables and prototype */Ptr gPreAllocatePointer;Boolean Have_Console = false; /* why try to use sioux console */WindowPtr Console_Window=NULL;WindowPtr Working_Window=NULL;SInt16 Edit_Window = 1;WindowPtr Graphic_Window[MAX_NUM_G_WIN + 1];WindowPtr Edit_Windows[MAX_NUM_E_WIN + 1];SInt16 Current_Window =1;SInt32 Num_Of_Window =1;SInt16 Edit_Number = 0;extern SInt16 gExpose;extern int EIGHTY, F_HEIGHT;extern Graphic_Ref gGReference[MAX_NUM_G_WIN + 1];extern gtabSize;extern SInt16 Help_Window, gTextSize;extern WindowPtr Help_Windows[MAX_NUM_H_WIN + 1];// some consts used by DoGrow()static void hideTextRect(Rect*);static SInt32 sScrollStep; // how many pixels to scroll (used by ScrollProc)extern void SetTab(void);extern int R_SetOptionWidth(int w);void RnWWin(char* buf, SInt16 len, WEReference we );enum {kMinWindowWidth = 200,kMinWindowHeight = 80};enum{kScrollStepTag = 'STEP' // user tag used to save scroll step information in scrollbars} ;/* CalcGrowIconRect*/static void CalcGrowIconRect( WindowPtr window, Rect *iconRect ){Rect portRect;GetWindowPortBounds ( window, & portRect );iconRect->top = portRect.bottom - (kBarWidth - 2);iconRect->left = portRect.right - (kBarWidth - 2);iconRect->bottom = portRect.bottom;iconRect->right = portRect.right;}/* CalcTextRect*/static void CalcTextRect( WindowPtr window, Rect *textRect ){Rect portRect;GetWindowPortBounds ( window, & portRect ) ;textRect->top = 0;textRect->left = 0;textRect->bottom = portRect.bottom - (kBarWidth - 1);textRect->right = portRect.right - (kBarWidth - 1);InsetRect( textRect, kTextMargin, kTextMargin );}/* CalcTextRect*/static void CalcBigTextRect( WindowPtr window, Rect *textRect ){Rect portRect;GetWindowPortBounds ( window, & portRect ) ;textRect->top = 0;textRect->left = 0;textRect->bottom = portRect.bottom - (kBarWidth - 1);textRect->right = 2000;InsetRect( textRect, kTextMargin, kTextMargin );}/* CalcScrollBarRect*/static void CalcScrollBarRect( WindowPtr window, Orientation orientation,Rect *barRect ){Rect portRect;GetWindowPortBounds ( window, & portRect ) ;switch ( orientation ){case kVertical :{barRect->top = -1;barRect->left = portRect.right - (kBarWidth - 1);barRect->bottom = portRect.bottom - (kBarWidth - 2);barRect->right = portRect.right + 1;break;}case kHorizontal :{barRect->top = portRect.bottom - (kBarWidth - 1);barRect->left = -1;barRect->bottom = portRect.bottom + 1;barRect->right = portRect.right - (kBarWidth - 2 );break;}}}/*the standard Toolbox trap _DrawGrowIcon draws two lines from thegrow icon to the left and top margins of the window's content areathese additional lines may create ugly dirt, so we use this routineto temporarily set the clip region to the grow icon rect.in addition, if validate is true, we call _ValidRect on the icon rect*/static void MyDrawGrowIcon( WindowPtr window, Boolean validate ){GrafPtr savePort;RgnHandle saveClip;Rect r;// save port and set thePort to windGetPort( &savePort );SetPortWindowPort( window );// save the clip regionsaveClip = NewRgn();GetClip( saveClip );// calculate the grow icon rectCalcGrowIconRect( window, &r );// set clip region to grow icon rectClipRect( &r );// call _DrawGrowIconDrawGrowIcon( window );// if validate is true, remove the grow icon rect from the update regionif ( validate )// ValidRect( &r );ValidWindowRect ( window, & r ) ;// restore old clip regionSetClip( saveClip );DisposeRgn( saveClip );// restore old portSetPort( savePort );}/* ScrollBarChanged*/static void ScrollBarChanged ( WindowRef window ){// scroll text to reflect new scroll bar settingDocumentHandle hDocument = GetWindowDocument ( window ) ;WEReference we = ( * hDocument ) -> we ;LongRect viewRect ;LongRect destRect ;WEGetViewRect ( & viewRect, we ) ;WEGetDestRect ( & destRect, we ) ;WEScroll(viewRect.left - destRect.left - GetControl32BitValue( (*hDocument)->scrollBars[ kHorizontal ] ),viewRect.top - destRect.top - GetControl32BitValue( (*hDocument)->scrollBars[ kVertical ] ),we);}static void AdjustBars ( WindowRef window ){DocumentHandle hDocument = GetWindowDocument ( window ) ;WEReference we = ( * hDocument ) -> we ;LongRect viewRect ;LongRect destRect ;SInt32 visible ;SInt32 total ;SInt32 value ;SInt32 max ;ControlRef bar ;// get the view and destination rectangleWEGetViewRect ( & viewRect, we ) ;WEGetDestRect ( & destRect, we ) ;// do the vertical axis// get scroll bar handlebar = ( * hDocument ) -> scrollBars [ kVertical ] ;// calculate new scroll bar settings// NOTE: (destRect.bottom - destRect.top) always equals the total text height because// WASTE automatically updates destRect.bottom whenever line breaks are recalculatedtotal = destRect . bottom - destRect . top ; // total pixel heightvisible = viewRect . bottom - viewRect . top ; // visible pixel heightmax = total - visible ; // scrollable range (in pixels)value = viewRect . top - destRect . top ; // thumb location within scrollable range// make sure max is always non-negativeif ( max <= 0 ) max = 0 ;// set visible sizeSetControlViewSize ( bar, visible ) ;// reset the scroll barSetControl32BitMaximum ( bar, max ) ;SetControl32BitValue ( bar, value ) ;// if value exceeds max then the bottom of the destRect is above// the bottom of the view rectangle: we need to scroll the text downwardif ( value > max ){ScrollBarChanged ( window ) ;}// now do the horizontal axis// get scroll bar handlebar = ( * hDocument ) -> scrollBars [ kHorizontal ] ;// calculate new scroll bar settingstotal = destRect . right - destRect . left ; // total pixel widthvisible = viewRect . right - viewRect . left ; // visible pixel widthmax = total - visible ; // scrollable range (in pixels)value = viewRect . left - destRect . left ; // thumb location within scrollable range// make sure max is always non-negativeif ( max <= 0 ) max = 0 ;// set visible sizeSetControlViewSize ( bar, visible ) ;// reset the scroll barSetControl32BitMaximum ( bar, max ) ;SetControl32BitValue ( bar, value ) ;}static void ViewChanged ( WindowRef window ){DocumentHandle hDocument ;ControlRef bar ;Rect r ;LongRect viewRect ;int orientation ;hDocument = GetWindowDocument ( window ) ;// resize the text areaCalcTextRect ( window, & r ) ;WERectToLongRect ( & r, & viewRect ) ;WESetViewRect ( & viewRect, ( * hDocument ) -> we ) ;// move and resize the control barsfor ( orientation = kVertical; orientation <= kHorizontal; orientation ++ ){bar = ( * hDocument ) -> scrollBars [ orientation ] ;HideControl ( bar ) ;CalcScrollBarRect ( window, orientation, & r ) ;#if TARGET_API_MAC_CARBONSetControlBounds ( bar, & r ) ;#else( * bar ) -> contrlRect = r ;#endifShowControl ( bar ) ;ValidWindowRect ( window, & r ) ;}// reset the thumb positions and the max values of the control barsAdjustBars ( window ) ;}DocumentHandle GetWindowDocument ( WindowRef window ){// make sure window is not nil and is one of our windowsif ( ( window == nil ) || ( GetWindowKind ( window ) != userKind ) ){return nil ;}// a handle to the document structure is kept in the window refConreturn ( DocumentHandle ) GetWRefCon ( window ) ;}WEReference GetWindowWE ( WindowRef window ){DocumentHandle document ;if ( ( document = GetWindowDocument ( window ) ) != nil ){return ( * document ) -> we ;}else{return nil ;}}void DoDrag ( Point thePoint, WindowRef window ){Rect desktopBounds ;DragWindow ( window, thePoint, GetRegionBounds ( GetGrayRgn ( ), & desktopBounds ) ) ;}/* DoGrow:When the console window grow, you need to reset the optionwidth. Unfortunately, the function CharWidth didn't doing the thing weexpected. We need to multiple a constant 0.75 (by experiment) to getthe best effect.*/void DoGrow ( Point hitPt, WindowRef window ){const Rect sizeConstraints = { kMinWindowHeight, kMinWindowWidth, 0x7FFF, 0x7FFF } ;Rect newContentRect ;Rect oldTextRect ;SInt32 newSize ;Rect sizeRect ;// remember original text rectangle/* if(isGraphicWindow(window))hideTextRect(&oldTextRect);else*/ CalcTextRect ( window, & oldTextRect ) ;// resize the windowif ( ! ResizeWindow ( window, hitPt, & sizeConstraints, & newContentRect ) )return ;if(isGraphicWindow(window))GraResize ( window ) ;else // resize the text areaWindowResized ( & oldTextRect, window ) ;}/* DoZoom*/void DoZoom ( SInt16 partCode, WindowRef window ){WEReference we = GetWindowWE ( window ) ;Rect portBounds ;Rect oldTextRect ;LongRect destRect ;SInt32 idealHeight ;Point idealSize ;// determine the ideal size for this window// the ideal height is the number of pixels needed to see the whole textWEGetDestRect ( & destRect, we ) ;idealHeight = ( destRect . bottom - destRect . top ) + ( 2 * kTextMargin + ( kBarWidth - 1 ) ) ;// the ideal height should always be at least kMinWindowHeightif ( idealHeight < kMinWindowHeight ){idealHeight = kMinWindowHeight ;}else if ( idealHeight > 0x7FFF ){// and must fit in a SInt16idealHeight = 0x7FFF ;}idealSize . v = idealHeight ;// since the text is automatically soft-wrapped to the window width,// there's no "ideal" window widthidealSize . h = GetWindowPortBounds ( window, & portBounds ) -> right ;// determine whether the window is currently in "standard" state or in "user" statepartCode = IsWindowInStandardState ( window, & idealSize, nil ) ? inZoomIn : inZoomOut ;// remember original text rectangle/* if(isGraphicWindow(window))hideTextRect(&oldTextRect);else*/ CalcTextRect ( window, & oldTextRect ) ;//CalcTextRect ( window, & oldTextRect ) ;// zoom the windowZoomWindowIdeal ( window, partCode, & idealSize ) ;if(isGraphicWindow(window))GraResize ( window ) ;else // resize the text areaWindowResized ( & oldTextRect, window ) ;}/* ScrollProc:this is a callback routine called by the Toolbox Control Manager movethe scroll bar thumb and scroll the text accordingly*/static pascal void ScrollProc ( ControlRef bar, ControlPartCode partCode ){switch ( partCode ){case kControlUpButtonPart :case kControlDownButtonPart :case kControlPageUpPart :case kControlPageDownPart :{SInt32 value = GetControl32BitValue ( bar ) ;SInt32 max = GetControl32BitMaximum ( bar ) ;SInt32 step = 0 ;UInt32 actualSize ;// retrieve precalculated step value from scroll barif ( GetControlProperty ( bar, R_ID, kScrollStepTag, sizeof ( step ),& actualSize, & step ) != noErr ){return ;}// move the scroll bar thumb by the precalculated step// and scroll the text accordinglyif ( ( ( value < max ) && ( step > 0 ) ) ||( ( value > 0 ) && ( step < 0 ) ) ){SetControl32BitValue ( bar, value + step ) ;ScrollBarChanged ( GetControlOwner ( bar ) ) ;}break ;}case kControlIndicatorPart :{ScrollBarChanged ( GetControlOwner ( bar ) ) ;break ;}}}static void WindowResized ( const Rect * oldTextRect, WindowRef window ){WEReference we = GetWindowWE ( window ) ;RgnHandle tempRgn ;RgnHandle dirtyRgn ;Rect r ;LongRect lr ;SInt16 oldTextWidth ;SInt16 newTextWidth ;SInt32 topCharOffset ;LongPt topCharPosition ;Boolean rewrapText = true ;SInt16 NumofChar;// create temporary regions for calculationstempRgn = NewRgn ( ) ;dirtyRgn = NewRgn ( ) ;// calculate original text widtholdTextWidth = ( oldTextRect -> right - oldTextRect -> left ) ;RectRgn ( tempRgn, oldTextRect ) ;// get new text rectCalcTextRect ( window, & r ) ;newTextWidth = ( r . right - r . left ) ;gTextSize = GetTextSize();if(window==Console_Window){TextFont(4);TextSize(gTextSize);NumofChar = (int)(((newTextWidth - 15) / CharWidth('M')) - 0.5) ;R_SetOptionWidth(NumofChar);}RectRgn ( dirtyRgn, & r ) ;// width changed?if ( newTextWidth == oldTextWidth ){// nope: no need to rewrap textrewrapText = false ;}if ( rewrapText ){// remember offset of first visible characterWEGetViewRect ( & lr, we ) ;topCharPosition = * ( LongPt * ) & lr ;topCharOffset = WEGetOffset ( & topCharPosition, nil, we ) ;// reset destination rectangle and recalculate line breaksWEGetDestRect ( & lr, we ) ;lr . right = lr . left + newTextWidth ;WESetDestRect ( & lr, we ) ;WECalText ( we ) ; // should check for errors!// scroll the destination rectangle to keep the previous// first visible character at the top of the view rectangleWEGetPoint ( topCharOffset, kHilite, & topCharPosition, nil, we ) ;WEGetDestRect ( & lr, we ) ;WEOffsetLongRect ( & lr, 0, kTextMargin - topCharPosition . v ) ;WESetDestRect ( & lr, we ) ;}ViewChanged ( window ) ;// calculate the dirty region (to be updated)if ( rewrapText ){InsetRgn ( dirtyRgn, - kTextMargin, - kTextMargin ) ;}else{XorRgn ( dirtyRgn, tempRgn, dirtyRgn ) ;InsetRect ( & r, - kTextMargin, - kTextMargin ) ;RectRgn ( tempRgn, & r ) ;SectRgn ( dirtyRgn, tempRgn, dirtyRgn ) ;}// mark the dirty region as invalidInvalWindowRgn ( window, dirtyRgn ) ;// throw away temporary regionsDisposeRgn ( tempRgn ) ;DisposeRgn ( dirtyRgn ) ;}/* DoScrollBar*/static void DoScrollBar ( Point hitPt, EventModifiers modifiers, WindowRef window ){DocumentHandle hDocument;ControlRef bar = nil;LongRect viewRect;ControlPartCode partCode;SInt32 pageSize;SInt32 step = 0;static ControlActionUPP sScrollerUPP = nil;if ( sScrollerUPP == nil ){sScrollerUPP = NewControlActionUPP ( ScrollProc ) ;}hDocument = GetWindowDocument ( window ) ;WEGetViewRect ( & viewRect, ( * hDocument ) -> we ) ;// find out which control was hit (if any) and in which partpartCode = FindControl ( hitPt, window, & bar ) ;// if any control was hit, it must be one of our two scroll bars:// find out which and calculate the page size for itif ( bar == ( * hDocument ) -> scrollBars [ kVertical ] ){pageSize = viewRect.bottom - viewRect.top ;}else if ( bar == ( * hDocument ) -> scrollBars [ kHorizontal ] ){pageSize = viewRect.right - viewRect.left ;}else{return; // return immediately if none of our scrollbars was hit}// calculate the "scroll step" according to the part hitswitch ( partCode ){case kControlUpButtonPart:{step = - ( ( modifiers & optionKey ) ? 1 : kScrollDelta ) ;break ;}case kControlDownButtonPart:{step = + ( ( modifiers & optionKey ) ? 1 : kScrollDelta ) ;break ;}case kControlPageUpPart:{step = - ( pageSize - kScrollDelta ) ;break ;}case kControlPageDownPart:{step = + ( pageSize - kScrollDelta ) ;break ;}} // switch// save scroll step as a control propertySetControlProperty ( bar, R_ID, kScrollStepTag, sizeof ( step ), & step ) ;// track the mouseTrackControl ( bar, hitPt, sScrollerUPP ) ;}/* TextScrolledThis is a callback routine called whenever the text is scrolledautomatically. Since auto-scrolling is enabled, WEScroll may beinvoked internally by WASTE in many different circumstances, and wewant to be notified when this happens so we can adjust the scrollbars*/static pascal void TextScrolled ( WEReference we ){WindowRef window = nil ;// get window reference associated with WE instanceif ( WEGetUserInfo ( kWindowTag, ( SInt32 * ) & window, we ) != noErr ){return ;}// make sure the scroll bars are in synch with the destination rectangleAdjustBars ( window ) ;}/* AddClippingName:*/static pascal OSErr AddClippingName ( DragReference drag, WEReference we ){// add a 'clnm' flavor containing the name of the document originating the drag// this flavor is used by the Finder (version 8.0 and later) to determine the// name of the clipping fileWindowRef window = nil ;Str255 windowTitle ;// get window reference associated with WE instanceif ( WEGetUserInfo ( kWindowTag, ( SInt32 * ) & window, we ) != noErr ){return paramErr ;}// get the window titleGetWTitle ( window, windowTitle ) ;// put the window title into the drag, as a 'clnm' flavor// we add this flavor to the same drag item used by WASTE to add the TEXT// (note that the reference number of this drag item = the WEReference )return AddDragItemFlavor ( drag, ( ItemReference ) we, kFlavorTypeClippingName, windowTitle,StrLength ( windowTitle ) + 1, flavorNotSaved ) ;}/* DoContent:This function will be called when you click inside the window*/Boolean DoContent ( Point hitPt, const EventRecord * event, WindowRef window ){WEReference we = GetWindowWE ( window ) ;Rect textRect ;GrafPtr savePort ;Boolean isMyClick = false ;// set up the portGetPort ( & savePort ) ;SetPortWindowPort ( window ) ;// convert the point to local coordinatesGlobalToLocal ( & hitPt ) ;// a click in an inactive window should normally activate it,// but the availability of the Drag Manager introduces an exception to this rule:// a click in the background selection may start a drag gesture,// without activating the windowif ( IsWindowHilited ( window ) ){isMyClick = true ; // active window -> always handle click}else{RgnHandle selRgn = WEGetHiliteRgn ( kCurrentSelection, kCurrentSelection, we ) ;isMyClick = PtInRgn ( hitPt, selRgn ) && WaitMouseMoved ( event -> where ) ;DisposeRgn ( selRgn ) ;}if ( isMyClick ){CalcTextRect ( window, & textRect ) ;if ( PtInRect ( hitPt, & textRect ) ){WEClick ( hitPt, event -> modifiers, event -> when, we ) ;}else{DoScrollBar ( hitPt, event -> modifiers, window ) ;}}// restore the portSetPort ( savePort ) ;// return true if the click should activate this windowreturn ! isMyClick ;}/* DoScrollKey:Handle Scroll key*/static void DoScrollKey ( SInt16 keyCode, WindowRef window ){DocumentHandle hDocument ;ControlRef bar ;SInt32 value ;LongRect viewRect ;hDocument = GetWindowDocument ( window ) ;bar = ( * hDocument ) -> scrollBars [ kVertical ] ;// get current scroll bar valuevalue = GetControl32BitValue ( bar ) ;// get text view rectWEGetViewRect ( & viewRect, ( * hDocument ) -> we ) ;switch ( keyCode ){case keyPgUp:{value -= ( viewRect . bottom - viewRect . top ) - kScrollDelta ;break ;}case keyPgDn:{value += ( viewRect . bottom - viewRect . top ) - kScrollDelta ;break ;}case keyHome:{value = 0 ;break ;}case keyEnd:{value = 0x7FFFFFFF ;break ;}} // switch// set the new scroll bar value and scroll the text pane accordinglySetControl32BitValue ( bar, value ) ;ScrollBarChanged ( window ) ;}/* DoKey :handle key event (keyPgUp, keyPgDn, keyHome ...)*/void DoKey ( SInt16 key, const EventRecord * event ){WindowRef window ;SInt16 keyCode ;// do nothing if no window is activeif ( ( window = FrontWindow ( ) ) == nil )return;// extract virtual key code from event recordkeyCode = ( event->message & keyCodeMask ) >> 8 ;// page movement keys are handled by DoScrollKey()switch ( keyCode ){case keyPgUp:case keyPgDn:case keyHome:case keyEnd:{DoScrollKey ( keyCode, window ) ;break ;}default:{WEKey ( key, event -> modifiers, GetWindowWE (window) ) ;break ;}}}/* DoUpdate:Based on WASTE DEMO. However, when you update a graphic window,you need to do something more than Text window.*/void DoUpdate ( WindowRef window ){GrafPtr savePort ;RgnHandle updateRgn ;SInt16 WinIndex;DevDesc *dd;#if TARGET_API_MAC_CARBONRect portRect ;#endif// if we have no windows, there's nothing to update!if ( window == nil ){return ;}// save the old drawing portGetPort ( & savePort ) ;SetPortWindowPort ( window ) ;// notify everything that we're doing an update.BeginUpdate ( window ) ;updateRgn = NewRgn ( ) ;#if TARGET_API_MAC_CARBON// set updateRgn to the whole window rectangle// in the future, when Carbon gives us an API to get the "drawable" region// of a window, use that!RectRgn ( updateRgn, GetWindowPortBounds ( window, & portRect ) ) ;#else// in a classic, non-Carbon environment, the visRgn of the window// is set to the region to redraw between BeginUpdate and EndUpdateMacCopyRgn ( window -> visRgn, updateRgn ) ;#endif// erase the update regionif(!isGraphicWindow(window))EraseRgn ( updateRgn ) ;// draw scroll barsif(!isGraphicWindow(window))UpdateControls ( window, updateRgn ) ;// draw textif(!isGraphicWindow(window))WEUpdate ( updateRgn, GetWindowWE ( window ) ) ;else{// if (QDIsPortBuffered(GetWindowPort(window)))// QDFlushPortBuffer(GetWindowPort(window), NULL);/* This way of refreshing windows is rather slow */WinIndex = isGraphicWindow(window);dd = (DevDesc*)gGReference[WinIndex].devdesc;playDisplayList(dd);}// tell everything we're done updatingEndUpdate ( window ) ;DisposeRgn ( updateRgn ) ;// restore the old graphics portSetPort ( savePort ) ;}/* DoActivate :Based on WASTE DEMO. However, when you activate a graphic window,you need to do something more than Text window.*/void DoActivate ( Boolean isActivating, WindowRef window ){DocumentHandle hDocument ;WEReference we ;GrafPtr savePort ;Rect barRect ;ControlPartCode barHilite ;SInt16 menuID ;int orientation ;// if this is not one of our document windows, nothing to do here...if ( ( hDocument = GetWindowDocument ( window ) ) == nil ){return ;}we = ( * hDocument ) -> we ;// sanity check: do nothing if required activation state// is the same as the current activation stateif ( isActivating == WEIsActive ( we ) ){return ;}// set up the portGetPort ( & savePort ) ;SetPortWindowPort ( window );// activate or deactivate the text (and any other relevant stuff) depending on just// what we're doing here...if ( isActivating ){WEActivate ( we ) ;barHilite = kControlNoPart ;}else{WEDeactivate ( we ) ;barHilite = kControlDisabledPart ;}// redraw the scroll bars with the new highlighting (and validate their rects)for ( orientation = kVertical ; orientation <= kHorizontal ; orientation ++ ){HiliteControl ( ( * hDocument ) -> scrollBars [ orientation ], barHilite ) ;CalcScrollBarRect ( window, orientation, & barRect ) ;ValidWindowRect ( window, & barRect ) ;}// if activating, undim text-related menusif ( isActivating ){for ( menuID = kMenuEdit ; menuID <= kMenuWindows ; menuID ++ ){EnableMenuItem ( GetMenuHandle ( menuID ), 0 ) ;}}// invalidate the menu barInvalMenuBar ( ) ;// restore the old graphics port..SetPort ( savePort ) ;}void DoIdle ( UInt32 * sleepTime, WindowRef window ){WEReference we = GetWindowWE ( window ) ;FSSpec spec ;// blink the caret if necessaryWEIdle ( sleepTime, we ) ;// update the window modification state according to the text modification count// (if this window has not been saved before, the proxy icon should remain dimmed// at all times)SetWindowModified ( window, ( WEGetModCount ( we ) > 0 ) ||( GetWindowProxyFSSpec ( window, & spec ) != noErr ) ) ;}/* CreateGraphicWindowThis routine is used to create a Graphic window. You need to resizethe window as the parameter specified.*/WindowPtr CreateGraphicWindow (int wid, int h){OSErr err;SInt16 WinIndex;Rect theWholeScreen;BitMap screenBits;err = newWindow (nil, nil, 1, false);if (!err){SizeWindow ( Working_Window, wid, h, false );GetQDGlobalsScreenBits(&screenBits);SetRect(&theWholeScreen, screenBits.bounds.left +4,screenBits.bounds.top +24, screenBits.bounds.right -4,screenBits.bounds.bottom -4);MoveWindow(Working_Window, theWholeScreen.right - wid - 5, theWholeScreen.top + 20, true);ShowWindow(Working_Window);if(Current_Window>2)RepositionWindow(FrontWindow(), Graphic_Window[Current_Window-2],kWindowCascadeOnParentWindow);}else{GWdoErrorAlert(eGWin);}return Working_Window;}/* CreateWindow:Create Text Window*/OSErr CreateWindow (const FSSpec * pFileSpec, Boolean editable){OSErr err;WindowPtr outWindow=nil;/* *outWindow = *Working_Window;err = newWindow (pFileSpec, &Working_Window, 0, editable);if (err)*Working_Window = *outWindow;*/outWindow = Working_Window;err = newWindow (pFileSpec, &Working_Window, 0, editable);if (err)Working_Window = outWindow;return err;}OSStatus newWindow ( const FSSpec * pFileSpec, WindowRef * outWindow, int graphic, Boolean editable ){static WEScrollUPP sScroller = nil ;static WEPreTrackDragUPP sPreTracker = nil ;Rect initialWindowBounds = { 48, 12, 48 + 280, 12 + 440 } ;const SInt32 translucencyThreshold = kStandardTranslucencyThreshold ;Str255 initialWindowTitle ;Cursor arrow ;DocumentHandle hDocument = nil ;WindowRef window = nil ;AliasHandle alias = nil ;WEReference we = nil ;ControlRef bar = nil ;Handle hPageMargins = nil ;PageMarginRec pageMargins ;FInfo finderInfo ;Rect textRect ;Rect fileRect ;const Rect * transitionSrcRect = nil ;LongRect lr ;int orientation ;OSStatus err ;Str255 titledString = "\pUntitled ";Str255 numberAsString;MenuHandle windowsMenu;WEStyleMode mode;TextStyle ts;OptionBits winOptions;BitMap screenBits;Rect theWholeScreen, portRect ;FMFontFamily fontFamily = 0 ;GetTextSize();initialWindowBounds.right = (int)(28 + EIGHTY);if(!Have_Console)initialWindowBounds.bottom = (int)(48 + 18*F_HEIGHT);switch(graphic){case 0:if(Edit_Window == MAX_NUM_E_WIN - 1){R_ShowMessage("Too may edit/help windows");err =-1;return;}break;default:if(Current_Window == MAX_NUM_G_WIN - 1){R_ShowMessage("Too many graphic windows");err =-1;return;}break;}// allocate UPPs first time thruif ( sScroller == nil ){sScroller = NewWEScrollUPP ( TextScrolled ) ;sPreTracker = NewWEPreTrackDragUPP ( AddClippingName ) ;}// allocate a relocateable block to hold a document recordhDocument = ( DocumentHandle ) NewHandleClear ( sizeof ( DocumentRecord ) ) ;if ( ( err = MemError( ) ) != noErr ){goto cleanup ;}// create the windowswitch(graphic){case 0:( * hDocument ) -> docType = kTypeText ;err = CreateNewWindow ( kDocumentWindowClass,kWindowCloseBoxAttribute | kWindowVerticalZoomAttribute | kWindowCollapseBoxAttribute | kWindowResizableAttribute,& initialWindowBounds, & window);break;default:window = GetNewCWindow ( kWindowTemplateID, nil, ( WindowPtr ) -1L ) ;if ( window == nil ){err = memFullErr ;goto cleanup ;}/*err = CreateNewWindow ( kDocumentWindowClass,kWindowCloseBoxAttribute | kWindowResizableAttribute, & initialWindowBounds, & window );*/break;}if(err!= noErr)goto cleanup;GetIndString ( initialWindowTitle, kMiscStringsID, 3 ) ;SetWTitle ( window, initialWindowTitle ) ;// link the document record to the window and the other way aroundSetWRefCon ( window, ( SInt32 ) hDocument ) ;( * hDocument ) -> owner = window ;// we got a window, so tell QuickDraw where to draw...SetPortWindowPort ( window ) ;// calculate the text rectangleif (graphic)hideTextRect(&textRect);elseCalcTextRect ( window, & textRect ) ;WERectToLongRect ( & textRect, & lr ) ;if(!Have_Console)winOptions = weDoAutoScroll | weDoOutlineHilite | weDoUndo | weDoMultipleUndo | weDoIntCutAndPaste |/* weDoDragAndDrop | */weDoUseTempMem | weDoDrawOffscreen ;elsewinOptions = weDoAutoScroll | weDoOutlineHilite | weDoUndo | weDoMultipleUndo | weDoIntCutAndPaste |/*weDoDragAndDrop | */weDoUseTempMem | weDoDrawOffscreen | weDoReadOnly ;if(Have_Console && editable)winOptions ^= weDoReadOnly ; /* in case a window is editable, we remove the 'readonly' tag */// create a new WASTE instanceif ( ( err = WENew ( & lr, & lr, winOptions, & we) ) != noErr ){goto cleanup ;}// save a reference to the window in the WE instanceif ( ( err = WESetUserInfo ( kWindowTag, ( SInt32 ) window, we ) ) != noErr ){goto cleanup ;}// now the other way around: save the WE reference in the document record( * hDocument ) -> we = we ;// set up our scroll callbackif ( ( err = WESetInfo ( weScrollProc, & sScroller, we ) ) != noErr ){goto cleanup ;}// set up our pre-TrackDrag callbackif ( ( err = WESetInfo ( wePreTrackDragHook, & sPreTracker, we ) ) != noErr ){goto cleanup ;}// enable translucent text draggingWESetInfo ( weTranslucencyThreshold, & translucencyThreshold, we ) ;// associate a default page margins record with the WE referencepageMargins . top = 72 << 16 ; // one inchpageMargins . bottom = 72 << 16 ;pageMargins . left = 72 << 16 ;pageMargins . right = 72 << 16 ;if ( ( err = PtrToHand ( & pageMargins, & hPageMargins, sizeof ( pageMargins ) ) ) != noErr ){goto cleanup ;}if ( ( err = WESetUserInfo ( kPageMarginsTag, ( SInt32 ) hPageMargins, we ) ) != noErr ){goto cleanup ;}hPageMargins = nil ;if(graphic==0){// create the scroll bars from a control templatefor ( orientation = kVertical ; orientation <= kHorizontal; orientation ++ ){Rect scrollBarRect ;CalcScrollBarRect ( window, orientation, & scrollBarRect ) ;if ( ( bar = NewControl ( window, & scrollBarRect, "\p", false, 0, 0, 0, kControlScrollBarLiveProc, 0 ) ) == nil ){err = memFullErr ;goto cleanup ;}HiliteControl ( bar, kControlDisabledPart ) ;ShowControl ( bar ) ;// save control handle in the document record( * hDocument ) -> scrollBars [ orientation ] = bar ;} // for} // graphic ==0// ViewChanged adjusts the scroll bars rectangles to the window frameif(graphic==0)ViewChanged ( window ) ;// if pFileSpec is not nil, it points to a file to read, so let's read it!if ( pFileSpec ){// turn the cursor into a wristwatch because this can be a lengthy operationSetCursor ( * GetCursor ( watchCursor ) ) ;// retrieve finder informationif ( ( err = FSpGetFInfo ( pFileSpec, & finderInfo ) ) != noErr ){goto cleanup ;}// read in the fileswitch ( finderInfo . fdType ){case kTypeText :{if ( ( err = ReadTextFile ( pFileSpec, we ) ) != noErr ){goto cleanup ;}break ;}case kTypeUnicodeText :{// read in the fileif ( ( err = ReadUnicodeTextFile ( pFileSpec, we ) ) != noErr ){goto cleanup ;}break ;}default :{err = badFileFormat ;goto cleanup ;}}if ( finderInfo . fdFlags & kIsStationery ){// the file we just read was a stationery pad, so don't associate it with the windowSetWindowProxyCreatorAndType ( window, finderInfo . fdCreator, finderInfo . fdType, pFileSpec -> vRefNum ) ;}else{// set the window titleSetWTitle ( window, pFileSpec -> name ) ;// set the window iconSetWindowProxyFSSpec ( window, pFileSpec ) ;SetWindowModified ( window, false ) ;}( * hDocument ) -> docType = finderInfo . fdType ;// get icon rectif ( GetFileRect ( pFileSpec, & fileRect ) == noErr ){transitionSrcRect = & fileRect ;}// make the cursor happySetCursor ( GetQDGlobalsArrow ( & arrow ) ) ;}else{SetWindowProxyCreatorAndType ( window, R_ID, kTypeText, kOnSystemDisk ) ;}// adjust scroll bar settings based on the total text heightif(!graphic)AdjustBars ( window ) ;// position the windowRepositionWindow ( window, FrontWindow ( ), kWindowCascadeOnParentWindow ) ;// finally! show the document windowTransitionWindow ( window, kWindowZoomTransitionEffect, kWindowShowTransitionAction, transitionSrcRect ) ;// copy window ref for callerif ( outWindow ){* outWindow = window ;}if (!Have_Console){SetWTitle(window, "\pR Console");Console_Window = window;Have_Console = true;}else{if (graphic == 0) {Edit_Windows[Edit_Window] = window;Edit_Window ++;Edit_Number ++;NumToString( Edit_Number ,numberAsString);GWdoConcatPStrings(titledString,numberAsString);SetWTitle(window, titledString);if(windowsMenu = GetMenuHandle(kMenuWindows))AppendMenu(windowsMenu, titledString);SetTab();GetQDGlobalsScreenBits(&screenBits);SetRect(&theWholeScreen, screenBits.bounds.left +4,screenBits.bounds.top +24, screenBits.bounds.right -4,screenBits.bounds.bottom -4);GetWindowPortBounds ( window, & portRect ) ;MoveWindow(window, theWholeScreen.right - (portRect.right + 5), theWholeScreen.top + 20, true);}}if (graphic){NumToString(Num_Of_Window,numberAsString);GWdoConcatPStrings(titledString,numberAsString);SetWTitle(window, titledString);/* We add the corresponding menu item somewhere else */Graphic_Window[Current_Window] = window;New_G_History(Current_Window);Current_Window++;Num_Of_Window++;}Working_Window = window;// finally! show the document windowif(systemVersion > kMinSystemVersion)fontFamily = FMGetFontFamilyFromName(UserFont);elseGetFNum(UserFont,&fontFamily);WESetOneAttribute ( kCurrentSelection, kCurrentSelection, weTagFontFamily,& fontFamily, sizeof ( fontFamily ), GetWindowWE ( window ) ) ;changeSize(window, gTextSize);cleanup :if ( err != noErr ){ErrorAlert ( err ) ;}ForgetHandle ( & hPageMargins ) ;return err ;}/* DestroyWindow*/void DestroyWindow ( WindowRef window ){DocumentHandle hDocument ;WEReference we ;#if TARGET_API_MAC_CARBONHandle hPageFormat = nil ;#elseHandle hPrintRecord = nil ;#endifHandle hPageMargins = nil ;FSSpec fileSpec ;Rect fileRect ;const Rect * transitionDstRect = nil ;SInt16 menuID ;hDocument = GetWindowDocument ( window ) ;we = ( * hDocument ) -> we ;#if TARGET_API_MAC_CARBON// get rid of the page format, if anyif ( WEGetUserInfo ( kPageFormatTag, ( SInt32 * ) & hPageFormat, we ) == noErr ){ForgetHandle ( & hPageFormat ) ;WERemoveUserInfo ( kPageFormatTag, we ) ;}#else// get rid of the print record, if anyif ( WEGetUserInfo ( kPrintRecordTag, ( SInt32 * ) & hPrintRecord, we ) == noErr ){ForgetHandle ( & hPrintRecord ) ;WERemoveUserInfo ( kPrintRecordTag, we ) ;}#endif// get rid of the page margin record, if anyif ( WEGetUserInfo ( kPageMarginsTag, ( SInt32 * ) & hPageMargins, we ) == noErr ){ForgetHandle ( & hPageMargins ) ;WERemoveUserInfo ( kPageMarginsTag, we ) ;}// destroy the WASTE instanceWEDispose ( we ) ;// if this document has an associated file, get its icon rectangleif ( ( GetWindowProxyFSSpec ( window, & fileSpec ) == noErr ) && ( GetFileRect ( & fileSpec, & fileRect ) == noErr ) ){transitionDstRect = & fileRect ;}// hide the windowTransitionWindow ( window, kWindowZoomTransitionEffect, kWindowHideTransitionAction, transitionDstRect ) ;// destroy the window record and all associated data structuresDisposeWindow ( window ) ;// finally, dispose of the document recordDisposeHandle ( ( Handle ) hDocument ) ;InvalMenuBar ( ) ;}/* hideTextRect:Used in Graphic window, which hide the corresponding TextEditField. We hide the TextField instead of creating another kind ofwindow, because the event processing procedure is based on the WASTEDEMO. Thus, if we have two different kind of window structure. Youneed to rewrite the event handling procedure too.*/static void hideTextRect( Rect *textRect ){textRect->top = 0;textRect->left = 0;textRect->bottom = 0;textRect->right = 0;InsetRect( textRect, kTextMargin, kTextMargin );}int isEditWindow(WindowPtr window){SInt16 i;for(i=1; i < Edit_Window; i++){if (Edit_Windows[i] == window)return i;}return 0;}void adjustEditPtr(SInt16 EditIndex){SInt16 i;for (i = EditIndex ; i < Edit_Window ; i++){Edit_Windows[i] = Edit_Windows[i+1];}Edit_Window --;}void adjustHelpPtr(SInt16 HelpIndex){SInt16 i;for (i = HelpIndex ; i < Help_Window ; i++){Help_Windows[i] = Help_Windows[i+1];}Help_Window --;}int R_ShowFiles(int nfile, char **fileName, char **title,char *WinTitle, Rboolean x, char *xx){Str255 PWTitle, Cur_Title, curString;Str255 name, numberAsString;FSSpec fsspec;OSErr readErr;SInt16 i;WEReference we;MenuHandle windowsMenu = NULL;Boolean EqString = FALSE;if (nfile <=0) return 1;readErr = DoNew(false);// Handle error for opening a new windowif (readErr != noErr)return 1;RemWinMenuItem();Help_Windows[Help_Window] = Edit_Windows[Edit_Window-1];if(Help_Window>1)RepositionWindow ( Help_Windows[Help_Window], Help_Windows[Help_Window-1], kWindowCascadeOnParentWindow ) ;Edit_Window --;Edit_Number --;Help_Window++;we = GetWindowWE ( Help_Windows[Help_Window-1]);for (i = 0; i < nfile; i++){if (title[i] && *title[i]){RnWWin(title[i], strlen(title[i]), we);RnWWin("\r\r", 2, we);}name[0] = strlen(fileName[i]);strncpy( (char *)(&name[1]),fileName[i], name[0] );FSMakeFSSpec(0,0,name,&fsspec);readErr = ReadTextFile ( &fsspec, we );if (readErr) {DoClose(0, savingNo, Help_Windows[Help_Window-1]);if(readErr == -43)warning("File not found");}UniqueWinTitle();}// Handle Error about readingreturn 1;}/* This routine determines a unique title for any text windowbased on the name of the file just openedJago April 2001, Stefano M. Iacus*/void UniqueWinTitle(void){Str255 pWTitle, ptestString, pcurString;char cWTitle[265], ctestString[265];MenuHandle windowsMenu;Boolean unique = false, EqString;int w_number = 1, i;GetWTitle(FrontWindow(), pWTitle);windowsMenu = GetMenuHandle(kMenuWindows);CopyPascalStringToC(pWTitle, cWTitle);CopyPascalStringToC(pWTitle, ctestString);CopyCStringToPascal(ctestString,ptestString);while(!unique){if(w_number>1)sprintf(ctestString,"%s [%d]",cWTitle, w_number);CopyCStringToPascal(ctestString,ptestString);for(i = 1; i <= CountMenuItems(windowsMenu); i++){GetMenuItemText(windowsMenu, i , pcurString);EqString = EqualNumString(ptestString, pcurString, ptestString[0]);if (EqString) {w_number++;unique = false;break;}elseunique = true;}}CopyPascalStringToC(ptestString, ctestString);AppendMenu(windowsMenu, ptestString);SetWTitle(FrontWindow(),ptestString);}/* This routine remove the menu item corresponding tothe title of the current FrontWindow()Jago April 2001, Stefano M. Iacus*/void RemWinMenuItem(void){Str255 pWTitle, pcurString;int i;MenuHandle windowsMenu = NULL;Boolean EqString;char cWTitle[260],ccurString[260];GetWTitle(FrontWindow(),pWTitle);CopyPascalStringToC(pWTitle,cWTitle);windowsMenu = GetMenuHandle(kMenuWindows);for(i = 1; i <= CountMenuItems(windowsMenu); i++){GetMenuItemText(windowsMenu, i , pcurString);CopyPascalStringToC(pcurString,ccurString);if (strcmp(ccurString,cWTitle) == 0) {DeleteMenuItem(windowsMenu, i);break;}}}void RnWWin(char* buf, SInt16 len, WEReference we ){SInt32 i;for ( i = 0; i < len; i++){WEKey ( buf[i], NULL, we ) ;}}int isHelpWindow(WindowPtr window){SInt16 i;for(i=1; i<Help_Window; i++){if (window == Help_Windows[i]){return i;}}return 0;}