/* * This file is subject to the terms of the GFX License. If a copy of * the license was not distributed with this file, you can obtain one at: * * http://ugfx.io/license.html */ /** * @file src/gwin/gwin_image.c * @brief GWIN sub-system image code */ #include "../../gfx.h" #if GFX_USE_GWIN && GWIN_NEED_IMAGE #include "gwin_class.h" #define gw ((GImageObject *)gh) static void ImageDestroy(GWindowObject *gh) { // Stop the timer #if GWIN_NEED_IMAGE_ANIMATION gtimerStop(&gw->timer); #endif if (gdispImageIsOpen(&gw->image)) gdispImageClose(&gw->image); } #if GWIN_NEED_IMAGE_ANIMATION static void ImageTimer(void *param) { _gwinUpdate((GHandle)param); } #endif static void ImageRedraw(GHandle gh) { gCoord x, y, w, h, dx, dy; gColor bg; #if GWIN_NEED_IMAGE_ANIMATION gDelay delay; #endif // The default display area dx = 0; dy = 0; x = gh->x; y = gh->y; w = gh->width; h = gh->height; bg = gwinGetDefaultBgColor(); // If the image isn't open just clear the area if (!gdispImageIsOpen(&gw->image)) { gdispGFillArea(gh->display, x, y, w, h, bg); return; } // Center horizontally if the area is larger than the image if (gw->image.width < w) { w = gw->image.width; dx = (gh->width-w)/2; x += dx; if (dx) gdispGFillArea(gh->display, gh->x, y, dx, h, bg); gdispGFillArea(gh->display, x+w, y, gh->width-dx-w, h, bg); dx = 0; } // Center image horizontally if the area is smaller than the image else if (gw->image.width > w) { dx = (gw->image.width - w)/2; } // Center vertically if the area is larger than the image if (gw->image.height < h) { h = gw->image.height; dy = (gh->height-h)/2; y += dy; if (dy) gdispGFillArea(gh->display, x, gh->y, w, dy, bg); gdispGFillArea(gh->display, x, y+h, w, gh->height-dy-h, bg); dy = 0; } // Center image vertically if the area is smaller than the image else if (gw->image.height > h) { dy = (gw->image.height - h)/2; } // Reset the background color in case it has changed gdispImageSetBgColor(&gw->image, bg); // Display the image gdispGImageDraw(gh->display, &gw->image, x, y, w, h, dx, dy); #if GWIN_NEED_IMAGE_ANIMATION // read the delay for the next frame delay = gdispImageNext(&gw->image); // Wait for that delay if required switch(delay) { case gDelayForever: // Everything is done break; case gDelayNone: // We can't allow a continuous loop here as it would lock the system up so we delay for the minimum period delay = 1; // Fall through default: // Start the timer to draw the next frame of the animation gtimerStart(&gw->timer, ImageTimer, (void*)gh, gFalse, delay); break; } #endif } static const gwinVMT imageVMT = { "Image", // The class name sizeof(GImageObject), // The object size ImageDestroy, // The destroy routine ImageRedraw, // The redraw routine 0, // The after-clear routine }; GHandle gwinGImageCreate(GDisplay *g, GImageObject *gobj, GWindowInit *pInit) { if (!(gobj = (GImageObject *)_gwindowCreate(g, &gobj->g, pInit, &imageVMT, 0))) return 0; // Ensure the gdispImageIsOpen() gives valid results gdispImageInit(&gobj->image); // Initialise the timer #if GWIN_NEED_IMAGE_ANIMATION gtimerInit(&gobj->timer); #endif gwinSetVisible((GHandle)gobj, pInit->show); return (GHandle)gobj; } gBool gwinImageOpenGFile(GHandle gh, GFILE *f) { // is it a valid handle? if (gh->vmt != (gwinVMT *)&imageVMT) return gFalse; if (gdispImageIsOpen(&gw->image)) gdispImageClose(&gw->image); if ((gdispImageOpenGFile(&gw->image, f) & GDISP_IMAGE_ERR_UNRECOVERABLE)) return gFalse; _gwinUpdate(gh); return gTrue; } gdispImageError gwinImageCache(GHandle gh) { // is it a valid handle? if (gh->vmt != (gwinVMT *)&imageVMT) return GDISP_IMAGE_ERR_BADFORMAT; return gdispImageCache(&gw->image); } #undef gw #endif // GFX_USE_GWIN && GWIN_NEED_IMAGE