Beispiel #1
0
void MCStack::view_update_transform(void)
{
	MCRectangle t_view_rect;
	MCGAffineTransform t_transform;
	
	// IM-2014-01-16: [[ StackScale ]] Use utility method to calculate new values
	view_calculate_viewports(m_view_requested_stack_rect, m_view_adjusted_stack_rect, t_view_rect, t_transform);
	
	// IM-2013-12-20: [[ ShowAll ]] Calculate new stack visible rect
	MCRectangle t_stack_visible_rect;
	t_stack_visible_rect = MCRectangleGetTransformedBounds(MCRectangleMake(0, 0, t_view_rect.width, t_view_rect.height), MCGAffineTransformInvert(t_transform));
	if (m_view_fullscreenmode == kMCStackFullscreenLetterbox || m_view_fullscreenmode == kMCStackFullscreenNoScale)
		t_stack_visible_rect = MCU_intersect_rect(t_stack_visible_rect, MCRectangleMake(0, 0, m_view_adjusted_stack_rect.width, m_view_adjusted_stack_rect.height));
	
	// IM-2013-10-03: [[ FullscreenMode ]] if the transform has changed, redraw everything
	// IM-2013-12-20: [[ ShowAll ]] if the stack viewport has changed, redraw everything
	if (!MCU_equal_rect(t_stack_visible_rect, m_view_stack_visible_rect) || !MCGAffineTransformIsEqual(t_transform, m_view_transform))
	{
		m_view_transform = t_transform;
		m_view_stack_visible_rect = t_stack_visible_rect;
		
		view_dirty_all();
	}
	
	// IM-2014-01-16: [[ StackScale ]] Update view rect if needed
	view_setrect(t_view_rect);
}
Beispiel #2
0
void MCStack::view_setrect(const MCRectangle &p_rect)
{
	if (MCU_equal_rect(p_rect, m_view_rect))
		return;
	
	MCRectangle t_old_rect;
	t_old_rect = m_view_rect;
	
	// IM-2013-10-08: [[ FullscreenMode ]] Update view rect before calling setsizehints()
	m_view_rect = p_rect;
	
	// IM-2014-01-16: [[ StackScale ]] Update window geometry if we have a window
	// IM-2014-02-27: [[ Bug 11858 ]] Allow window geometry update when stack is closed
	if (window != nil)
	{
		// IM-2013-10-03: [[ FullscreenMode ]] if the view rect has changed, update the window geometry

		// IM-2014-01-24: [[ HiDPI ]] Change to use logical coordinates - device coordinate conversion no longer needed
		/* CODE REMOVED */

		// IM-2013-10-08: [[ FullscreenMode ]] Update window size hints when setting the view geometry.
		setsizehints();
		view_setgeom(m_view_rect);
	}
	
	view_on_rect_changed();
}
Beispiel #3
0
void MCStack::view_configure(bool p_user)
{
	MCRectangle t_view_rect;
	mode_getrealrect(t_view_rect);

	// IM-2014-09-23: [[ Bug 13349 ]] If window geometry change occurs while there's a pending resize
	//    then use the requested rect rather than the new one.
	if (m_view_need_resize)
		t_view_rect = m_view_rect;
	
	if (!MCU_equal_rect(t_view_rect, m_view_rect))
	{
		// IM-2014-02-13: [[ StackScale ]] Test if the view size has changed
		bool t_resize;
		t_resize = t_view_rect.width != m_view_rect.width || t_view_rect.height != m_view_rect.height;
		
		m_view_rect = t_view_rect;
		
		view_on_rect_changed();
		
		if (view_getfullscreen())
		{
			// IM-2014-01-16: [[ StackScale ]] recalculate fullscreenmode transform after view rect change
			view_update_transform();
		}
		else
		{
			uint32_t t_current_width, t_current_height;
			t_current_width = m_view_adjusted_stack_rect.width;
			t_current_height = m_view_adjusted_stack_rect.height;
			
			// IM-2014-01-16: [[ StackScale ]] set the stack rects to the scaled down view rect
			m_view_requested_stack_rect = m_view_adjusted_stack_rect = MCRectangleGetTransformedBounds(m_view_rect, MCGAffineTransformInvert(m_view_transform));
			
			// IM-2014-02-13: [[ StackScale ]] If the view size has not changed then make sure
			//   the stack size also remains the same
			if (!t_resize)
			{
				//restore current logical width & height
				m_view_requested_stack_rect.width = m_view_adjusted_stack_rect.width = t_current_width;
				m_view_requested_stack_rect.height = m_view_adjusted_stack_rect.height = t_current_height;
			}
			
			// IM-2014-02-06: [[ ShowAll ]] Update the visible stack rect
			m_view_stack_visible_rect = MCRectangleMake(0, 0, m_view_adjusted_stack_rect.width, m_view_adjusted_stack_rect.height);
		}
	}
	configure(p_user);
}
Beispiel #4
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));
		}
	}
}
Beispiel #5
0
bool MCGIFImageLoader::LoadFrames(MCBitmapFrame *&r_frames, uint32_t &r_count)
{
	bool t_success;
	t_success = true;
	
	MCImageBitmap *t_canvas;
	t_canvas = nil;
	
	// restoration info
	MCImageBitmap *t_restore_image = nil;
	int t_disposal_mode = DISPOSAL_UNSPECIFIED;
	MCRectangle t_disposal_region = kMCEmptyRectangle;

	// The list of frames.
	MCBitmapFrame *t_frames = nil;

	t_success = GIF_OK == DGifSlurp(m_gif);

	// Fetch the width and height of the virtual canvas.
	int32_t t_width, t_height;

	if (t_success)
	{
		t_width = m_gif -> SWidth;
		t_height = m_gif -> SHeight;

		// create the canvas image
		t_success = MCImageBitmapCreate(t_width, t_height, t_canvas);
	}

	// The current frame count. The number of frames is the same as the
	// number of images in the GIF.
	uint32_t t_frame_count;
	t_frame_count = 0;
	
	// If true, the new image will be merged with the old - otherwise the mask
	// replaces it.
	bool t_overlay;
	t_overlay = false;
	
	// Loop through all the images, making frames as we go.
	for(uindex_t i = 0; t_success && i < m_gif -> ImageCount; i++)
	{
		// Process the disposal.
		switch (t_disposal_mode)
		{
		case DISPOSE_BACKGROUND:
			gif_fill_image_region(t_canvas, t_disposal_region, 0);
			break;

		case DISPOSE_PREVIOUS:
			if (t_restore_image != nil)
				gif_paste_image(t_canvas, t_restore_image, t_disposal_region.x, t_disposal_region.y);
			break;

		case DISPOSE_DO_NOT:
			t_overlay = true;
			break;

		default:
			t_overlay = false;
			break;
		}

		// Fetch the image information.
		GraphicsControlBlock t_image_gcb;
		MCRectangle t_image_region;
		ColorMapObject *t_image_colors = nil;
		int32_t t_image_transparency;
		int32_t t_image_delay;
		int32_t t_image_disposal;
		GifByteType *t_image_raster;

		// First the information from the image description.
		t_image_region.x = m_gif -> SavedImages[i] . ImageDesc . Left;
		t_image_region.y = m_gif -> SavedImages[i] . ImageDesc . Top;
		t_image_region.width = m_gif -> SavedImages[i] . ImageDesc . Width;
		t_image_region.height = m_gif -> SavedImages[i] . ImageDesc . Height;
		t_image_colors = m_gif -> SavedImages[i] . ImageDesc . ColorMap;
		t_image_raster = m_gif -> SavedImages[i] . RasterBits;
		if (t_image_colors == nil)
			t_image_colors = m_gif -> SColorMap;
		
		// Then the information from the GCB.
		if (GIF_OK == DGifSavedExtensionToGCB(m_gif, i, &t_image_gcb))
		{
			t_image_transparency = t_image_gcb . TransparentColor;
			t_image_delay = t_image_gcb . DelayTime;
			t_image_disposal = t_image_gcb . DisposalMode;
		}
		else
		{
			t_image_transparency = -1;
			t_image_delay = 0;
			t_image_disposal = DISPOSAL_UNSPECIFIED;
			}
			
		// If disposal is 'previous' then cache the portion of the canvas we are
		// about to affect.
		if (t_image_disposal == DISPOSE_PREVIOUS)
			{
			if (t_restore_image != nil)
			{
				if (t_disposal_mode != DISPOSE_PREVIOUS ||
					!MCU_equal_rect(t_disposal_region, t_image_region))
				{
					MCImageFreeBitmap(t_restore_image);
					t_restore_image = nil;
				}
			}
			if (t_restore_image == nil)
				t_success = MCImageCopyBitmapRegion(t_canvas, t_image_region, t_restore_image);
		}
		
		if (t_success)
		{
			// Render the image into the canvas.
			gif_draw_image_into_canvas(t_canvas, t_image_raster,
				t_image_region.x, t_image_region.y, t_image_region.width, t_image_region.height,
				t_image_colors, t_image_transparency, t_overlay);
			
			// Generate our frame.
			t_success = MCMemoryResizeArray(t_frame_count + 1, t_frames, t_frame_count);
		}

		MCImageBitmap *t_frame_bitmap = nil;
		if (t_success)
			t_success = MCImageCopyBitmap(t_canvas, t_frame_bitmap);
			
		if (t_success)
		{
			MCImageBitmapCheckTransparency(t_frame_bitmap);
			t_frames[t_frame_count - 1].image = t_frame_bitmap;
			t_frames[t_frame_count - 1].duration = t_image_delay * 10; // convert 1/100 seconds to milliseconds
			t_frames[t_frame_count - 1].x_scale = t_frames[t_frame_count - 1].y_scale = 1.0;
		}

		t_disposal_region = t_image_region;
		t_disposal_mode = t_image_disposal;
	}
	
	MCImageFreeBitmap(t_canvas);
	MCImageFreeBitmap(t_restore_image);
	
	if (t_success)
	{
		r_frames = t_frames;
		r_count = t_frame_count;
	}
	else
		MCImageFreeFrames(t_frames, t_frame_count);

	return t_success;
}
Beispiel #6
0
void MCStack::view_update_transform(bool p_ensure_onscreen)
{
	MCRectangle t_view_rect;
	MCGAffineTransform t_transform;
    
#if defined(_MOBILE)
    MCOrientation t_orientation;
    MCSystemGetOrientation(t_orientation);
    MCOrientationGetRectForOrientation(t_orientation ,m_view_requested_stack_rect);
#endif
	
	// IM-2014-01-16: [[ StackScale ]] Use utility method to calculate new values
	view_calculate_viewports(m_view_requested_stack_rect, m_view_adjusted_stack_rect, t_view_rect, t_transform);
	
	// IM-2013-12-20: [[ ShowAll ]] Calculate new stack visible rect
	MCRectangle t_stack_visible_rect;
	t_stack_visible_rect = MCRectangleGetTransformedBounds(MCRectangleMake(0, 0, t_view_rect.width, t_view_rect.height), MCGAffineTransformInvert(t_transform));
	if (m_view_fullscreenmode == kMCStackFullscreenLetterbox || m_view_fullscreenmode == kMCStackFullscreenNoScale)
		t_stack_visible_rect = MCU_intersect_rect(t_stack_visible_rect, MCRectangleMake(0, 0, m_view_adjusted_stack_rect.width, m_view_adjusted_stack_rect.height));
	
	// IM-2013-10-03: [[ FullscreenMode ]] if the transform has changed, redraw everything
	// IM-2013-12-20: [[ ShowAll ]] if the stack viewport has changed, redraw everything
	bool t_rect_changed, t_transform_changed;
	t_rect_changed = !MCU_equal_rect(t_stack_visible_rect, m_view_stack_visible_rect);
	t_transform_changed = !MCGAffineTransformIsEqual(t_transform, m_view_transform);
	if (t_rect_changed || t_transform_changed)
	{
		m_view_transform = t_transform;
		m_view_stack_visible_rect = t_stack_visible_rect;
		
		dirtyall();
		if (t_transform_changed)
			this->OnViewTransformChanged();
	}
	
	// PM-2015-07-17: [[ Bug 13754 ]] Make sure stack does not disappear off screen when changing the scalefactor
    MCRectangle t_bounded_rect;
    if (p_ensure_onscreen)
    {
        // AL-2015-10-01: [[ Bug 16017 ]] Remember location of stacks on a second monitor
        const MCDisplay* t_nearest_display;
        t_nearest_display = MCscreen -> getnearestdisplay(t_view_rect);
        
        if (t_nearest_display != nil)
        {
			MCRectangle t_screen_rect;
            t_screen_rect = t_nearest_display -> viewport;
            t_bounded_rect = MCU_bound_rect(t_view_rect, t_screen_rect . x, t_screen_rect . y, t_screen_rect . width, t_screen_rect . height);
        }
        else
        {
            // In noUI mode, we don't have a nearest display.
            t_bounded_rect = MCU_bound_rect(t_view_rect, 0, 0, MCscreen -> getwidth(), MCscreen -> getheight());
        }
    }
    else
    {
        t_bounded_rect = t_view_rect;
    }
    
    // IM-2014-01-16: [[ StackScale ]] Update view rect if needed
    view_setrect(t_bounded_rect);
}