home *** CD-ROM | disk | FTP | other *** search
- /*
- ***********************************************************************
- *
- * Simple Window Class
- * A generic simple window that can be dragged around the screen
- * and closed by clicking a "go-away" button
- * No other events are handled, redefine the event handler if necessary.
- *
- *
- ***********************************************************************
- */
-
- #include "image.h"
- #include "mymenv.h"
- #include "window.h"
- //#include <PictUtil.h>
-
- /*
- *----------------------------------------------------------------------
- * Service functions
- */
-
- // Getting a bounding rectangle of an image
- ScreenRect::ScreenRect(const IMAGE& image)
- {
- left = top = 0;
- right = image.q_ncols();
- bottom = image.q_nrows();
- }
-
- #if 0
-
- // Create a rectangle of given height/width
- // positioned at the origin
- ScreenRect::ScreenRect(const rowcol& heightwidth)
- {
- left = top = 0;
- bottom = heightwidth.row();
- right = heightwidth.col();
- }
-
- // Create a rectangle of given height/width
- // positioned at a given point
- ScreenRect::ScreenRect(const rowcol& origin, const rowcol& heightwidth)
- {
- top = origin.row();
- left = origin.col();
- bottom = top+heightwidth.row();
- right = left+heightwidth.col();
- }
- #endif
-
-
- // Shifting a rectangle by the same amount
- // in X and Y
- ScreenRect& ScreenRect::operator += (const int offset)
- {
- top += offset; bottom += offset; left += offset; right += offset;
- return *this;
- }
-
-
- // Print what rectangle is this
- void ScreenRect::print(const char * title) const
- {
- alert("Rectangle %s (%d,%d) - (%d,%d)",title,top,left,bottom,right);
- }
-
-
- #if 0
- /*
- *----------------------------------------------------------------------
- * Primitive Window creators/destructors
- */
-
- // This is a protected constructor. Normally
- // objects XVTBasicWindow are created as a part
- // of a derived class
- XVTBasicWindow::XVTBasicWindow(void)
- {
- Not_canceled = FALSE;
- this_window = NULL_WIN;
- }
-
- // Destroy the window if it hasn't been destroyed
- // already
- XVTBasicWindow::~XVTBasicWindow(void)
- {
- if( this_window != 0 )
- close_window(this_window);
- }
-
- // Close the window
- void XVTBasicWindow::cancel(void)
- {
- Not_canceled = FALSE;
- if( this_window != 0 )
- close_window(this_window);
- }
-
- /*
- *----------------------------------------------------------------------
- * Basic event dispatching/handling
- */
-
- // A universal event handler: does almost nothing
- // but watches creation and destruction of windows
- // (to tell when there are no windows to watch)
- // For any other tasks, it calls the handler of
- // a particular window
- int XVTBasicWindow::no_opened_windows = 0;
- long XVTBasicWindow::universal_handler(WINDOW win, EVENT *ep)
-
- {
- XVTBasicWindow& the_window = *(XVTBasicWindow *)get_app_data(win);
-
- if( ep->type == E_CREATE )
- no_opened_windows++, the_window.this_window = win;
-
- the_window.handler(*ep);
-
- // XVT would destroy the window after this
- // event
- if( ep->type == E_DESTROY )
- no_opened_windows--, the_window.this_window = 0;
-
- return 0;
- }
-
- // Serve the windows until all get closed
- void XVTBasicWindow::serve_to_death(void)
- {
- while( no_opened_windows>0 )
- process_events();
- }
-
-
- // Event handler for a particular window
- // Finally, a handler which really does smth
- // specific
- void XVTBasicWindow::handler(EVENT event)
- {
- switch(event.type)
- {
- case E_CREATE:
- if( !initialize() )
- cancel();
- break;
- }
- }
-
- /*
- *----------------------------------------------------------------------
- * Window creators
- *
- * Note, event processing may start *before* the create_* functions return!
- * So, if initialize() or event handlers, etc rely on some data that are
- * going to be initialized *after* create_* function, you're in trouble!
- * It's better to call create() function the last thing in the constructor,
- * or even not to call at all (call it separetely later) to allow derived
- * classes initialize properly!
- *
- */
- #endif
-
- /*
- *----------------------------------------------------------------------
- * Window creators
- */
-
- // Create a color window of the specified size and title
- // Note, the upper left corner of 'rect' must
- // NOT be (0,0)!
- ScreenWindow::ScreenWindow(ScreenRect rect, const char * title)
- {
- const int window_offset = 100; // Cannot be 0 or small!
- this_window = NewCWindow(nil,rect += window_offset,(Pstr)title,
- TRUE,noGrowDocProc,
- (WindowPtr)(-1),TRUE,(long)this);
- assert( this_window != 0 );
- SetPort(this_window);
- SelectWindow(this_window);
- }
-
- // Create a color window from a resource template
- ScreenWindow::ScreenWindow(const short resource_id)
- {
- this_window = GetNewCWindow(resource_id,nil,(WindowPtr)(-1));
- SetWRefCon(this_window,(long)this);
- assert( this_window != 0 );
- SetPort(this_window);
- SelectWindow(this_window);
- }
-
-
- // I wouldn't've needed this is destructor had been really virtual. Right now,
- // CW 6.0 accepts attribute virtual for the destructor, but doesn't override
- // destructors as it does for virtual functions. Oh, well, another kludge
-
- // Close the window and clean up the rubble
- void ScreenWindow::destroy_it(void)
- {
- assert( this_window != 0 );
- DisposeWindow(this_window);
- this_window = 0;
- }
-
- /*
- *----------------------------------------------------------------------
- * Basic Even Handling
- */
-
- // Top-level event dispatcher
- // Returns FALSE when the window is to be destroyed
- // and won't need any further events
- Boolean ScreenWindow::handle_event(const EventRecord& the_event)
- {
- switch( the_event.what )
- {
- case mouseDown:
- WindowPtr wp;
- short windowPart = FindWindow(the_event.where, &wp);
- if( !handle_mouse_down(the_event,wp,windowPart) )
- return FALSE; // Window is to be closed (go-away buttin clicked)
- break;
-
- case updateEvt:
- if( this_window == (WindowPtr)the_event.message )
- update();
- break;
-
- case keyDown:
- case autoKey:
- if( !handle_key_down(the_event) )
- return FALSE; // a "quit" key must've been pressed
- break;
-
- case activateEvt:
- if( this_window == (WindowPtr)the_event.message )
- if( the_event.modifiers & 0x01 )
- SetPort(this_window);
- }
- return TRUE;
- }
-
- // Handle "mouse-down" events
- // Returns FALSE if the user clicked within the
- // go-away region of our window. Otherwise,
- // returns TRUE
- // Handles dragging if necessary and system clicks
- Boolean ScreenWindow::handle_mouse_down
- (const EventRecord& the_event, WindowPtr where_window, short window_part)
- {
- switch( window_part )
- {
- case inSysWindow:
- SystemClick(&the_event, where_window);
- break;
-
- case inMenuBar:
- break; // Don't handle it yet
-
- case inContent:
- break;
-
- case inDrag:
- if( this_window == where_window )
- DragWindow(this_window,the_event.where,&qd.screenBits.bounds);
- break;
-
- case inGoAway:
- return !TrackGoAway(where_window, the_event.where);
- }
- return TRUE;
- }
-
- // Handles key_down & auto_key events. Return FALSE
- // if the window is to be closed down
- Boolean ScreenWindow::handle_key_down(const EventRecord& the_event)
- {
- return FALSE; // Any key kills the application, sorry
- }
-
-
- // Handles null events, when nothing happens for some
- // time. Return FALSE when it's time to die
- Boolean ScreenWindow::handle_null_event(const long event_time)
- {
- return TRUE; // Keep going
- }
-
-
-
- // Private window parts
- // Handle an update event - redraw the window
- // A virtual function draw() is called to do
- // the actual redrawing
- void ScreenWindow::update(void)
- {
- SetNewGrafPtr((GrafPtr)this_window);
- BeginUpdate(this_window);
- draw();
- EndUpdate(this_window);
- }
-
- // Make the entire window being redrawn
- void ScreenWindow::refresh(void)
- {
- InvalRect(&this_window->portRect);
- }
-
-
- /*
- *----------------------------------------------------------------------
- * An off-screen pixel buffer for faster drawing
- */
-
- // Allocate the buffer for offscreen
- // drawing and load a CLUT (if clut_id != 0)
- OffScreenBuffer::OffScreenBuffer(ScreenRect rect, const short clut_id)
- : graf_world(nil)
- {
- CTabHandle clut_handle = nil;
- if( clut_id != 0 )
- { // try to get a user CLUT with that resource id
- clut_handle = GetCTable(clut_id);
- assert( clut_handle != 0 );
- }
- do_well( NewGWorld(&graf_world,8,rect,clut_handle,nil,0) );
- assert( graf_world != nil );
-
- if( clut_handle != nil )
- DisposCTable(clut_handle); // CLUT has been copied, and can be disposed of now
-
- // Get hold of the offscreen pixmap
- pixmap = GetGWorldPixMap(graf_world); // and make sure it looks like
- assert( pixmap != nil && *pixmap != nil ); // we can use it
-
- assert( (**pixmap).cmpCount == 1 ); // We have a color table index
- assert( !PixMap32Bit(pixmap) );
-
- _height = abs((**pixmap).bounds.top - (**pixmap).bounds.bottom);
- _width = abs((**pixmap).bounds.right - (**pixmap).bounds.left);
- _bytes_per_row = (**pixmap).rowBytes & 0x7fff;
-
- assert( _height > 0 && _height < 10000 ); // Just to play safe
- assert( _width > 0 && _width <= _bytes_per_row );
- }
-
- // Dispose of the offscreen buffer
- OffScreenBuffer::~OffScreenBuffer(void)
- {
- assert( graf_world != nil );
- DisposeGWorld(graf_world);
- graf_world = nil;
- #if 0
- PaletteHandle window_palette = GetPalette(our_window());
- if( window_palette != nil ) // dispose of our palette if was allocated
- {
- SetPalette(our_window(),nil,FALSE);
- DisposePalette(window_palette);
- }
- #endif
- pixmap = nil;
- _height = _width = _bytes_per_row = 0;
- }
-
- #if 0
- // Make sure that the colors of our off-screen
- // buffer would be displayed properly (or close enough)
- // on screen
- void OffScreenBuffer::activate_palette(void)
- {
- CTabHandle window_ctab = (**pixmap).pmTable;
- assert( window_ctab != nil && *window_ctab != nil );
-
- PaletteHandle palette = NewPalette((**window_ctab).ctSize,window_ctab,pmTolerant+pmExplicit,0);
- assert( palette != nil );
- SetPalette(our_window(),palette,TRUE);
- do_well( QDError() );
- ActivatePalette(our_window());
- do_well( QDError() );
- }
- #endif
-
-
- // Actual drawing - moving the picture from the
- // offscreen grafworld to the onscreen one, to the current port.
- // Remember to set a device to that of the offscreen
- // grafworld before CopyBits (in order to get grafworld's color table and
- // inverse color table to be used): see IM, Palette Manager
- // Also note, if a window we're going to draw on is partly/completely
- // obscured, then the visRgn, the visible region of the on-screen window,
- // is *not* a window rectangle. When we make the offscreen grafworld the
- // current grafport for CopyBits, CopyBits has no way of knowing then that
- // the true destination region may not be the whole where_rect at all. To make
- // CopyBits aware of the fact that the onscreen window maybe abscured, we
- // pass the visRgn of the onscreen window as a clipping region to CopyBits.
- // In that case CopyBits performs clipping just as if the onscreen window
- // where the current grafport.
- // Note, to be really precise, we ought to pass CopyBits() an intersection of
- // onscreen grafport's visRgn and clipRgn. Well, we take a shortcut here:
- // normally clipRgn is set to be the whole screen. Moreover, visRgn is clipped
- // already not only to the unobscured part of the window, but to the update
- // region as well. So using visRgn only should suffice....
- // Also make sure that the onscreen window has a palette roughly corresponding
- // to the CLUT of the grafworld (otherwise colors would be screwed up)
- // One can use a palette resource 0 to be used as a default palette for
- // dialogs/windows within the task
- void OffScreenBuffer::draw(const Rect& where_rect, const Rect& from_rect)
- {
- // const BitMap * where_pixmap = &qd.thePort->portBits; // see below
- CGrafPtr old_port;
- GDHandle old_gdevice;
- GetGWorld(&old_port,&old_gdevice);
- const RgnHandle where_visible_region = old_port->visRgn;
- SetGWorld((CGrafPtr)graf_world,nil);
- // The following line is actually the same as
- // the one commented at the very top. However,
- // thePort stuff doesn't work under OpenDoc, but
- // the following line does.
- const BitMap * where_pixmap = &((GrafPtr)old_port)->portBits;
- //!!!Set_NewGrafWorld((GWorldPtr)graf_world); // Doesn't work: CW disposes of the object too early
- assert( LockPixels(pixmap) );
- CopyBits((const BitMap *)*pixmap, where_pixmap, &from_rect, &where_rect, /*ditherCopy*/ srcCopy, where_visible_region);
- SetGWorld(old_port,old_gdevice);
- UnlockPixels(pixmap);
- }
-