Exemple #1
0
void MCCard::layer_setviewport(int32_t p_x, int32_t p_y, int32_t p_width, int32_t p_height)
{
	MCTileCacheRef t_tilecache;
	t_tilecache = getstack() -> gettilecache();

	// Notify any tilecache of the changes.
	if (t_tilecache != nil)
		MCTileCacheSetViewport(t_tilecache, MCU_make_rect(p_x, p_y, p_width, p_height));

	// Get the current rect, before updating it.
	MCRectangle t_old_rect;
	t_old_rect = rect;
	
	// Update the rect.
	resize(p_width, p_height);
	
	// Add the rects to the update region.

	// MW-2012-05-01: [[ Bug 10157 ]] If the card has a border then add the whole card
	//   rect to the update region; otherwise just add the exposed rects.
	if (!getflag(F_SHOW_BORDER))
	{
		if (p_width > t_old_rect.width)
			layer_dirtyrect(MCU_make_rect(t_old_rect.width, 0, p_width - t_old_rect.width, p_height));
		if (p_height > t_old_rect.height)
			layer_dirtyrect(MCU_make_rect(0, t_old_rect.height, p_width, p_height - t_old_rect.height));
	}
	else
		layer_dirtyrect(rect);
}
Exemple #2
0
// MW-2011-10-17: [[ Bug 9813 ]] We need the effective rect before visibility is
//   changed, else focus border might be not included in our calculation.
void MCControl::layer_visibilitychanged(const MCRectangle& p_old_effective_rect)
{
	if (!opened)
		return;

	if (!parent -> isvisible() && !MCshowinvisibles)
		return;

	// If the control is currently visible, then its old rect must have been
	// empty; otherwise the old rect is its effectiverect.
	layer_changeeffectiverect(getflag(F_VISIBLE) ? MCU_make_rect(0, 0, 0, 0) : p_old_effective_rect, false, true);
}
Exemple #3
0
bool MCStack::view_snapshottilecache(const MCRectangle &p_stack_rect, MCGImageRef &r_image)
{
	if (m_view_tilecache == nil)
		return false;
	
	// MW-2013-10-29: [[ Bug 11330 ]] Transform stack to (local) view co-ords.
	MCRectangle t_view_rect;
	t_view_rect = MCRectangleGetTransformedBounds(p_stack_rect, getviewtransform());
	t_view_rect = MCU_intersect_rect(t_view_rect, MCU_make_rect(0, 0, view_getrect() . width, view_getrect() . height));
	
	// IM-2014-01-24: [[ HiDPI ]] use backing surface coords for tilecache operations
	MCRectangle t_device_rect;
	t_device_rect = MCRectangleGetScaledBounds(t_view_rect, view_getbackingscale());
	return MCTileCacheSnapshot(m_view_tilecache, t_device_rect, r_image);
}
Exemple #4
0
	bool LockPixels(MCRegionRef p_area, MCGRaster &r_raster)
	{
		m_locked_bits = m_raster.pixels;
		m_locked_stride = m_raster.stride;

		m_locked_area = MCRegionGetBoundingBox(p_area);
		// restrict locked area to intersection with raster
		m_locked_area = MCU_intersect_rect(m_locked_area, MCU_make_rect(0, 0, m_raster.width, m_raster.height));

		/* UNCHECKED */ MCRegionIncludeRect(m_redraw_region, m_locked_area);

		r_raster.width = m_locked_area.width;
		r_raster.height = m_locked_area.height;
		r_raster.pixels = (uint8_t *)m_locked_bits + m_locked_area . y * m_locked_stride + m_locked_area . x * sizeof(uint32_t);
		r_raster.stride = m_locked_stride;
		r_raster.format = m_raster.format;
		return true;
	}
Exemple #5
0
void MCCard::render(void)
{
	MCTileCacheRef t_tiler;
	t_tiler = getstack() -> gettilecache();

	bool t_reset_ids;
	t_reset_ids = MCTileCacheIsClean(t_tiler);

	if (getstate(CS_SIZE))
	{
		MCTileCacheLayer t_fg_layer;
		t_fg_layer . id = m_fg_layer_id;
		t_fg_layer . region = selrect;
		t_fg_layer . is_opaque = false;
		t_fg_layer . opacity = 255;
		t_fg_layer . ink = GXblendSrcOver;
		t_fg_layer . callback = render_foreground;
		t_fg_layer . context = this;
		MCTileCacheRenderScenery(t_tiler, t_fg_layer);
		m_fg_layer_id = t_fg_layer . id;
	}
	else
		m_fg_layer_id = 0;

	MCObjptr *t_objptrs;
	t_objptrs = getobjptrs();
	if (t_objptrs != nil)
	{
		MCObjptr *t_objptr;
		t_objptr = t_objptrs -> prev();
		do
		{
			MCControl *t_control;
			t_control = t_objptr -> getref();

			// If the tilecache is 'clean' then we must reset the attrs to
			// force a sync.
			if (t_reset_ids)
				t_control -> layer_resetattrs();

			// Take note of whether the spriteness of a layer has changed.
			bool t_old_is_sprite;
			t_old_is_sprite = t_control -> layer_issprite();

			// Sync the attributes, make sure we commit the new values.
			t_control -> layer_computeattrs(true);

			// Initialize the common layer props.
			MCTileCacheLayer t_layer;
			t_layer . id = t_control -> layer_getid();
			t_layer . opacity = t_control -> getopacity();
			t_layer . ink = t_control -> getink();
			t_layer . context = t_control;

			// The opaqueness of a layer has already been computed.
			t_layer . is_opaque = t_control -> layer_isopaque();

			// Now compute the layer's region/clip.
			if (!t_control -> getflag(F_VISIBLE) && !MCshowinvisibles)
			{
				// Invisible layers just have empty region/clip.
				t_layer . region = MCU_make_rect(0, 0, 0, 0);
				t_layer . clip = MCU_make_rect(0, 0, 0, 0);
			}
			else if (!t_control -> layer_isscrolling())
			{
				// Non-scrolling layer's are the size of their effective rects.
				t_layer . region = t_control -> geteffectiverect();
				t_layer . clip = t_layer . region;
			}
			else
			{
				// For a scrolling layer, the clip is the bounds of the control, while
				// the region we draw is the group's minrect.
				t_layer . region = t_control -> layer_getcontentrect();
				t_layer . clip = t_control -> geteffectiverect();
			}

			// Now render the layer - what method we use depends on whether the
			// layer is a sprite or not.
			if (t_control -> layer_issprite())
			{
				// If the layer was not a sprite before, remove the scenery
				// layer that it was.
				if (!t_old_is_sprite && t_layer . id != 0)
				{
					MCTileCacheRemoveScenery(t_tiler, t_layer . id, t_control -> geteffectiverect());
					t_layer . id = 0;
				}

				t_layer . callback = testtilecache_sprite_renderer;
				MCTileCacheRenderSprite(t_tiler, t_layer);
			}
			else
			{
				// If the layer was a sprite before, remove the sprite
				// layer that it was.
				if (t_old_is_sprite && t_layer . id != 0)
				{
					MCTileCacheRemoveSprite(t_tiler, t_layer . id);
					t_layer . id = 0;
				}

				t_layer . callback = testtilecache_scenery_renderer;
				MCTileCacheRenderScenery(t_tiler, t_layer);
			}
			
			// Upate the id.
			t_control -> layer_setid(t_layer . id);

			// Advance to the object below.
			t_objptr = t_objptr -> prev();
		}
		while(t_objptr != t_objptrs -> prev());
	}

	// Final step is to render the background. Note that the background layer
	// really only needs to be the rect rounded outward to the nearest tile
	// boundaries, but 8192, 8192 is bigger than it can ever be at present so
	// is an easier alternative.
	MCTileCacheLayer t_bg_layer;
	t_bg_layer . id = m_bg_layer_id;
	t_bg_layer . region = MCU_make_rect(0, 0, 8192, 8192);
	t_bg_layer . is_opaque = true;
	t_bg_layer . opacity = 255;
	t_bg_layer . ink = GXblendSrcOver;
	t_bg_layer . callback = render_background;
	t_bg_layer . context = this;
	MCTileCacheRenderScenery(t_tiler, t_bg_layer);
	m_bg_layer_id = t_bg_layer . id;
}
Exemple #6
0
void MCControl::layer_changeeffectiverect(const MCRectangle& p_old_effective_rect, bool p_force_update, bool p_update_card)
{
	// Compute the 'new' effectiverect based on visibility.
	MCRectangle t_new_effective_rect;
	if (getflag(F_VISIBLE) || MCshowinvisibles)
		t_new_effective_rect = geteffectiverect();
	else
		MCU_set_rect(t_new_effective_rect, 0, 0, 0, 0);

	// If the effective rect has not changed this is at most an update.
	if (MCU_equal_rect(p_old_effective_rect, t_new_effective_rect))
	{
		// If we are forcing an update, use the dirty method.
		if (p_force_update)
		{
			// If the layer is not scrolling just defer to the normal
			// dirty method; otherwise use the dirty content method.
			if (!layer_isscrolling())
				layer_dirtyeffectiverect(t_new_effective_rect, p_update_card);
			else
				layer_dirtycontentrect(layer_getcontentrect(), p_update_card);
		}

		// We are done.
		return;
	}

	// Fetch the tilecache, making it nil if the parent is a group (in the
	// latter case, this is just a dirty op).
	MCTileCacheRef t_tilecache;
	if (parent -> gettype() != CT_GROUP)
		t_tilecache = getstack() -> gettilecache();
	else
		t_tilecache = nil;
	
	// If no tilecache, then just dirty the old and new effective rects.
	if (t_tilecache == nil)
	{
		layer_dirtyeffectiverect(p_old_effective_rect, p_update_card);
		layer_dirtyeffectiverect(t_new_effective_rect, p_update_card);
		return;
	}

	// MW-2011-10-17: [[ Bug 9808 ]] Make sure we update the card regardless of
	//    whether we have a layer id - otherwise new objects don't show!
	// Add the rects to the update region - but only if instructed (update_card will be
	// false if the object was invisible).
	if (p_update_card)
	{
		static_cast<MCCard *>(parent) -> layer_dirtyrect(p_old_effective_rect);
		static_cast<MCCard *>(parent) -> layer_dirtyrect(t_new_effective_rect);
	}
	
	// We must be in tile-cache mode with a top-level control, but if the layer
	// id is zero, there is nothing to do.
	if (m_layer_id == 0)
		return;

	if (!layer_issprite())
	{
		// Non-dynamic layers are scenery in the tilecache, and we must use old
		// new effective rects so that the appropriate tiles get flushed. Note
		// that 'force_update' has no effect here as reshaping a scenery layer
		// implicitly invalidates all tiles it touches.
		MCTileCacheReshapeScenery(t_tilecache, m_layer_id, p_old_effective_rect, t_new_effective_rect);
	}
	else
	{
		// Dynamic layers are sprites in the tilecache, and there is nothing to
		// do unless 'force update' is required. In particular, if the layer is
		// just moving then no redraw of the layer will be needed. Note, however,
		// that this implicitly assumes that 'force update' is true if the content
		// in a sprite-relative co-ord system has changed.
		if (p_force_update)
		{
			MCRectangle t_rect;
			
			// If the layer is not scrolling, just use the width/height from the
			// effective rect; otherwise use content width/height.
			if (!layer_isscrolling())
				t_rect = p_old_effective_rect;
			else
				t_rect = layer_getcontentrect();
				
			MCTileCacheUpdateSprite(t_tilecache, m_layer_id, MCU_make_rect(0, 0, t_rect . width, t_rect . height));
		}
	}
}
Exemple #7
0
void MCStack::effectrect(const MCRectangle& p_area, Boolean& r_abort)
{
	// Get the list of effects.
	MCEffectList *t_effects = MCcur_effects;
	MCcur_effects = NULL;

	// If the window isn't opened or hasn't been attached (plugin) or if we have no
	// snapshot to use, this is a no-op.
	if (!opened || !haswindow() || m_snapshot == nil)
	{
		while(t_effects != NULL)
		{
			MCEffectList *t_effect;
			t_effect = t_effects;
			t_effects = t_effects -> next;
			delete t_effect;
		}
		return;
	}

	// Mark the stack as being in an effect.
	state |= CS_EFFECT;

	// Lock messages while the effect is happening.
	Boolean t_old_lockmessages;
	t_old_lockmessages = MClockmessages;
	MClockmessages = True;

	// Calculate the area of interest.
	MCRectangle t_effect_area;
	t_effect_area = curcard -> getrect();
	t_effect_area . y = getscroll();
	t_effect_area . height -= t_effect_area . y;
	t_effect_area = MCU_intersect_rect(t_effect_area, p_area);
	
	// IM-2013-08-21: [[ ResIndependence ]] Scale effect area to device coords
	// Align snapshot rect to device pixels
	// IM-2013-09-30: [[ FullscreenMode ]] Use stack transform to get device coords
	MCGAffineTransform t_transform;
	t_transform = getdevicetransform();
	
    // MW-2013-10-29: [[ Bug 11330 ]] Make sure the effect area is cropped to the visible
    //   area.
    t_effect_area = MCRectangleGetTransformedBounds(t_effect_area, getviewtransform());
    t_effect_area = MCU_intersect_rect(t_effect_area, MCU_make_rect(0, 0, view_getrect() . width, view_getrect() . height));
	
	// IM-2014-01-24: [[ HiDPI ]] scale effect region to backing surface coords
	MCGFloat t_scale;
	t_scale = view_getbackingscale();
	
    MCRectangle t_device_rect, t_user_rect;
	t_device_rect = MCRectangleGetScaledBounds(t_effect_area, t_scale);
	t_user_rect = MCRectangleGetTransformedBounds(t_device_rect, MCGAffineTransformInvert(t_transform));
	
	// IM-2013-08-29: [[ RefactorGraphics ]] get device height for CoreImage effects
	// IM-2013-09-30: [[ FullscreenMode ]] Use view rect to get device height
	uint32_t t_device_height;
	t_device_height = floor(view_getrect().height * t_scale);
	
	// Make a region of the effect area
	// IM-2013-08-29: [[ ResIndependence ]] scale effect region to device coords
	MCRegionRef t_effect_region;
	t_effect_region = nil;
	/* UNCHECKED */ MCRegionCreate(t_effect_region);
	/* UNCHECKED */ MCRegionSetRect(t_effect_region, t_effect_area);
	
#ifndef FEATURE_PLATFORM_PLAYER
#if defined(FEATURE_QUICKTIME)
	// MW-2010-07-07: Make sure QT is only loaded if we actually are doing an effect
	if (t_effects != nil)
		if (!MCdontuseQTeffects)
			if (!MCtemplateplayer -> isQTinitted())
				MCtemplateplayer -> initqt();
#endif	
#endif

	// Lock the screen to prevent any updates occuring until we want them.
	MCRedrawLockScreen();

	// By default, we have not aborted.
	r_abort = False;
	
	MCGImageRef t_initial_image;
	t_initial_image = MCGImageRetain(m_snapshot);
	
	while(t_effects != nil)
	{
		uint32_t t_duration;
		t_duration = MCU_max(1, MCeffectrate / (t_effects -> speed - VE_VERY));
		if (t_effects -> type == VE_DISSOLVE)
			t_duration *= 2;
		
		uint32_t t_delta;
		t_delta = 0;
		
		// Create surface at effect_area size.
		// Render into surface based on t_effects -> image
		MCGImageRef t_final_image = nil;
		
		// If this isn't a plain effect, then we must fetch first and last images.
		if (t_effects -> type != VE_PLAIN)
		{
			// Render the final image.
			MCGContextRef t_context = nil;
			
			// IM-2014-05-20: [[ GraphicsPerformance ]] Create opaque context for snapshot
			/* UNCHECKED */ MCGContextCreate(t_device_rect.width, t_device_rect.height, false, t_context);
			
			MCGContextTranslateCTM(t_context, -t_device_rect.x, -t_device_rect.y);
			
			// IM-2013-10-03: [[ FullscreenMode ]] Apply device transform to context
			MCGContextConcatCTM(t_context, t_transform);
			
			// Configure the context.
			MCGContextClipToRect(t_context, MCRectangleToMCGRectangle(t_user_rect));
			
			// Render an appropriate image
			switch(t_effects -> image)
			{
				case VE_INVERSE:
					{
						MCContext *t_old_context = nil;
						/* UNCHECKED */ t_old_context = new MCGraphicsContext(t_context);
						curcard->draw(t_old_context, t_user_rect, false);
						delete t_old_context;
						
						MCGContextSetFillRGBAColor(t_context, 1.0, 1.0, 1.0, 1.0);
						MCGContextSetBlendMode(t_context, kMCGBlendModeDifference);
						MCGContextAddRectangle(t_context, MCRectangleToMCGRectangle(t_user_rect));
						MCGContextFill(t_context);
					}
					break;
					
				case VE_BLACK:
					MCGContextSetFillRGBAColor(t_context, 0.0, 0.0, 0.0, 1.0);
					MCGContextAddRectangle(t_context, MCRectangleToMCGRectangle(t_user_rect));
					MCGContextFill(t_context);
					break;
					
				case VE_WHITE:
					MCGContextSetFillRGBAColor(t_context, 1.0, 1.0, 1.0, 1.0);
					MCGContextAddRectangle(t_context, MCRectangleToMCGRectangle(t_user_rect));
					MCGContextFill(t_context);
					break;
					
				case VE_GRAY:
					MCGContextSetFillRGBAColor(t_context, 0.5, 0.5, 0.5, 1.0);
					MCGContextAddRectangle(t_context, MCRectangleToMCGRectangle(t_user_rect));
					MCGContextFill(t_context);
					break;
					
				default:
				{
					MCContext *t_old_context = nil;
					/* UNCHECKED */ t_old_context = new MCGraphicsContext(t_context);
					curcard->draw(t_old_context, t_user_rect, false);
					delete t_old_context;
				}
			}
			
			/* UNCHECKED */ MCGContextCopyImage(t_context, t_final_image);
			MCGContextRelease(t_context);
		}
		
		MCStackEffectContext t_context;
		t_context.delta = t_delta;
		t_context.duration = t_duration;
		t_context.effect = t_effects;
		t_context.effect_area = t_device_rect;
		t_context.initial_image = t_initial_image;
		t_context.final_image = t_final_image;
		
		// MW-2011-10-20: [[ Bug 9824 ]] Make sure dst point is correct.
		// Initialize the destination with the start image.
		view_platform_updatewindowwithcallback(t_effect_region, MCStackRenderInitial, &t_context);
		
		// If there is a sound, then start playing it.
		if (t_effects -> sound != NULL)
		{
			MCAudioClip *acptr;
            MCNewAutoNameRef t_sound;
            /* UNCHECKED */ MCNameCreate(t_effects->sound, &t_sound);
			if ((acptr = (MCAudioClip *)getobjname(CT_AUDIO_CLIP, *t_sound)) == NULL)
			{
				IO_handle stream;
				if ((stream = MCS_open(t_effects->sound, kMCOpenFileModeRead, True, False, 0)) != NULL)
				{
					acptr = new MCAudioClip;
					acptr->setdisposable();
					if (!acptr->import(t_effects->sound, stream))
					{
						delete acptr;
						acptr = NULL;
					}
					MCS_close(stream);
				}
			}
			
			if (acptr != NULL)
			{
				MCU_play_stop();
				MCacptr = acptr;
				MCU_play();
#ifndef FEATURE_PLATFORM_AUDIO
				if (MCacptr != NULL)
					MCscreen->addtimer(MCacptr, MCM_internal, PLAY_RATE);
#endif
			}
			
			if (MCscreen->wait((real8)MCsyncrate / 1000.0, False, True))
			{
				r_abort = True;
				break;
			}
		}
		
		// Initialize CoreImage of QTEffects if needed.
		if (t_effects -> type != VE_PLAIN)
		{
            MCAutoPointer<char> t_name;
            /* UNCHECKED */ MCStringConvertToCString(t_effects -> name, &t_name);
#ifdef _MAC_DESKTOP
			// IM-2013-08-29: [[ ResIndependence ]] use scaled effect rect for CI effects
			if (t_effects -> type == VE_UNDEFINED && MCCoreImageEffectBegin(*t_name, t_initial_image, t_final_image, t_device_rect, t_device_height, t_effects -> arguments))
				t_effects -> type = VE_CIEFFECT;
			else
#endif
#ifdef FEATURE_QUICKTIME_EFFECTS
				// IM-2013-08-29: [[ ResIndependence ]] use scaled effect rect for QT effects
				if (t_effects -> type == VE_UNDEFINED && MCQTEffectBegin(t_effects -> type, *t_name, t_effects -> direction, t_initial_image, t_final_image, t_device_rect))
					t_effects -> type = VE_QTEFFECT;
#else
				;
#endif
		}
		
		// Run effect
		// Now perform the effect loop, but only if there is something to do.
		if (t_effects -> type != VE_PLAIN || old_blendlevel != blendlevel)
		{
			// Calculate timing parameters.
			double t_start_time;
			t_start_time = 0.0;
			
			for(;;)
			{
				t_context.delta = t_delta;
				
				Boolean t_drawn = False;
				view_platform_updatewindowwithcallback(t_effect_region, MCStackRenderEffect, &t_context);
				
				// Now redraw the window with the new image.
//				if (t_drawn)
				{
					MCscreen -> sync(getw());
				}
				
				// Update the window's blendlevel (if needed)
				if (old_blendlevel != blendlevel)
				{
					float t_fraction = float(t_delta) / t_duration;
					setopacity(uint1((old_blendlevel * 255 + (float(blendlevel) - old_blendlevel) * 255 * t_fraction) / 100));
				}
				
				// If the start time is zero, then start counting from here.
				if (t_start_time == 0.0)
					t_start_time = MCS_time();
				
				// If we've reached the end of the transition, we are done.
				if (t_delta == t_duration)
				{
#ifdef _ANDROID_MOBILE
					// MW-2011-12-12: [[ Bug 9907 ]] Make sure we let the screen sync at this point
					MCscreen -> wait(0.01, False, False);
#endif
					break;
				}
				
				// Get the time now.
				double t_now;
				t_now = MCS_time();
				
				// Compute the new delta value.
				uint32_t t_new_delta;
				t_new_delta = (uint32_t)ceil((t_now - t_start_time) * 1000.0);
				
				// If the new value is same as the old, then advance one step.
				if (t_new_delta == t_delta)
					t_delta = t_new_delta + 1;
				else
					t_delta = t_new_delta;
				
				// If the new delta is beyond the end point, set it to the end.
				if (t_delta > t_duration)
					t_delta = t_duration;
				
				// Wait until the next boundary, making sure we break for no reason
				// other than abort.
				if (MCscreen -> wait((t_start_time + (t_delta / 1000.0)) - t_now, False, False))
					r_abort = True;
				
				// If we aborted, we render the final step and are thus done.
				if (r_abort)
					t_delta = t_duration;
			}
		}		
#ifdef _MAC_DESKTOP
		if (t_effects -> type == VE_CIEFFECT)
			MCCoreImageEffectEnd();
		else
#endif
#ifdef FEATURE_QUICKTIME_EFFECTS
			if (t_effects -> type == VE_QTEFFECT)
				MCQTEffectEnd();
#endif
		
		// Free initial surface.
		MCGImageRelease(t_initial_image);
		
		// initial surface becomes final surface.
		t_initial_image = t_final_image;
		t_final_image = nil;
		
		// Move to the next effect.
		MCEffectList *t_current_effect;
		t_current_effect = t_effects;
		t_effects = t_effects -> next;
		delete t_current_effect;
	}

	// Make sure the pixmaps are freed and any dangling effects
	// are cleaned up.
	if (t_effects != NULL)
	{
		/* OVERHAUL - REVISIT: error cleanup needs revised */
		MCGImageRelease(t_initial_image);
//		MCGSurfaceRelease(t_final_image);

		while(t_effects != NULL)
		{
			MCEffectList *t_current_effect;
			t_current_effect = t_effects;
			t_effects = t_effects -> next;
			delete t_current_effect;
		}
	}

	MCRegionDestroy(t_effect_region);
	
	MCGImageRelease(m_snapshot);
	m_snapshot = nil;
	
	m_snapshot = t_initial_image;
	
	// Unlock the screen.
	MCRedrawUnlockScreen();
	
	// Unlock messages.
	MClockmessages = t_old_lockmessages;

	// Turn off effect mode.
	state &= ~CS_EFFECT;
	
	// The stack's blendlevel is now the new one.
	old_blendlevel = blendlevel;
	
	// Finally, mark the affected area of the stack for a redraw.
	dirtyrect(p_area);
}
Exemple #8
0
bool MCUIDC::device_getwindowgeometry(Window p_window, MCRectangle &r_rect)
{
	r_rect = MCU_make_rect(0, 0, 32, 32);
	return true;
}
Exemple #9
0
MCRectangle MCRegionGetBoundingBox(MCRegionRef self)
{
	Rect t_rect;
	GetRegionBounds((RgnHandle)self, &t_rect);
	return MCU_make_rect(t_rect . left, t_rect . top, t_rect . right - t_rect . left, t_rect . bottom - t_rect . top);
}