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); }
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(); }
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); }
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)); } } }
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; }
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); }