Restored bitmap buttons in demo toolbar. Added image load/save APIs. Removed duplicate image handling code.
This commit is contained in:
parent
fddd97ad91
commit
fd695afac8
8 changed files with 205 additions and 163 deletions
|
|
@ -583,18 +583,39 @@ static void setupControlsWindow(void) {
|
|||
|
||||
WidgetT *tb = wgtToolbar(page5tb);
|
||||
|
||||
WidgetT *btnNew = wgtButton(tb, "&New");
|
||||
char iconPath[272];
|
||||
snprintf(iconPath, sizeof(iconPath), "%s/new.bmp", sDxeCtx->appDir);
|
||||
WidgetT *btnNew = wgtImageButtonFromFile(tb, iconPath);
|
||||
|
||||
if (!btnNew) {
|
||||
btnNew = wgtButton(tb, "&New");
|
||||
}
|
||||
|
||||
btnNew->onClick = onToolbarClick;
|
||||
WidgetT *btnOpen = wgtButton(tb, "&Open");
|
||||
|
||||
snprintf(iconPath, sizeof(iconPath), "%s/open.bmp", sDxeCtx->appDir);
|
||||
WidgetT *btnOpen = wgtImageButtonFromFile(tb, iconPath);
|
||||
|
||||
if (!btnOpen) {
|
||||
btnOpen = wgtButton(tb, "&Open");
|
||||
}
|
||||
|
||||
btnOpen->onClick = onToolbarClick;
|
||||
WidgetT *btnSave = wgtButton(tb, "&Save");
|
||||
|
||||
snprintf(iconPath, sizeof(iconPath), "%s/save.bmp", sDxeCtx->appDir);
|
||||
WidgetT *btnSave = wgtImageButtonFromFile(tb, iconPath);
|
||||
|
||||
if (!btnSave) {
|
||||
btnSave = wgtButton(tb, "&Save");
|
||||
}
|
||||
|
||||
btnSave->onClick = onToolbarClick;
|
||||
|
||||
wgtVSeparator(tb);
|
||||
WidgetT *btnHelp = wgtButton(tb, "&Help");
|
||||
btnHelp->onClick = onToolbarClick;
|
||||
|
||||
wgtLabel(page5tb, "Toolbar with text buttons and VSeparator.");
|
||||
wgtLabel(page5tb, "Toolbar with image buttons, text fallback, and VSeparator.");
|
||||
|
||||
// --- Tab 6: Media (Image from file) ---
|
||||
WidgetT *page6m = wgtTabPage(tabs, "&Media");
|
||||
|
|
|
|||
108
dvx/dvxApp.c
108
dvx/dvxApp.c
|
|
@ -40,6 +40,7 @@
|
|||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "thirdparty/stb_image.h"
|
||||
#include "thirdparty/stb_image_write.h"
|
||||
|
||||
// Double-click timing uses CLOCKS_PER_SEC so it's portable between DJGPP
|
||||
|
|
@ -1447,6 +1448,15 @@ void dvxFreeAccelTable(AccelTableT *table) {
|
|||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// dvxFreeImage
|
||||
// ============================================================
|
||||
|
||||
void dvxFreeImage(uint8_t *data) {
|
||||
free(data);
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// dvxGetBlitOps
|
||||
// ============================================================
|
||||
|
|
@ -1549,6 +1559,75 @@ int32_t dvxInit(AppContextT *ctx, int32_t requestedW, int32_t requestedH, int32_
|
|||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// dvxLoadImage
|
||||
// ============================================================
|
||||
//
|
||||
// Public image loading API. Loads any image file supported by stb_image
|
||||
// (BMP, PNG, JPEG, GIF, etc.) and converts the RGB pixels to the
|
||||
// display's native pixel format for direct use with rectCopy, wgtImage,
|
||||
// wgtImageButton, or any other pixel-data consumer. The caller owns the
|
||||
// returned buffer and must free it with dvxFreeImage().
|
||||
|
||||
uint8_t *dvxLoadImage(const AppContextT *ctx, const char *path, int32_t *outW, int32_t *outH, int32_t *outPitch) {
|
||||
if (!ctx || !path) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const DisplayT *d = &ctx->display;
|
||||
|
||||
int imgW;
|
||||
int imgH;
|
||||
int channels;
|
||||
uint8_t *rgb = stbi_load(path, &imgW, &imgH, &channels, 3);
|
||||
|
||||
if (!rgb) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t bpp = d->format.bytesPerPixel;
|
||||
int32_t pitch = imgW * bpp;
|
||||
uint8_t *buf = (uint8_t *)malloc(pitch * imgH);
|
||||
|
||||
if (!buf) {
|
||||
stbi_image_free(rgb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (int32_t y = 0; y < imgH; y++) {
|
||||
for (int32_t x = 0; x < imgW; x++) {
|
||||
const uint8_t *src = rgb + (y * imgW + x) * 3;
|
||||
uint32_t color = packColor(d, src[0], src[1], src[2]);
|
||||
uint8_t *dst = buf + y * pitch + x * bpp;
|
||||
|
||||
if (bpp == 1) {
|
||||
*dst = (uint8_t)color;
|
||||
} else if (bpp == 2) {
|
||||
*(uint16_t *)dst = (uint16_t)color;
|
||||
} else {
|
||||
*(uint32_t *)dst = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stbi_image_free(rgb);
|
||||
|
||||
if (outW) {
|
||||
*outW = imgW;
|
||||
}
|
||||
|
||||
if (outH) {
|
||||
*outH = imgH;
|
||||
}
|
||||
|
||||
if (outPitch) {
|
||||
*outPitch = pitch;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// dvxInvalidateRect
|
||||
// ============================================================
|
||||
|
|
@ -1692,6 +1771,35 @@ bool dvxUpdate(AppContextT *ctx) {
|
|||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// dvxSaveImage
|
||||
// ============================================================
|
||||
//
|
||||
// Save native-format pixel data to a PNG file. Converts from the
|
||||
// display's native pixel format to RGB, then encodes as PNG via
|
||||
// stb_image_write. This is the general-purpose image save function;
|
||||
// dvxScreenshot and dvxWindowScreenshot are convenience wrappers
|
||||
// around it for common use cases.
|
||||
|
||||
int32_t dvxSaveImage(const AppContextT *ctx, const uint8_t *data, int32_t w, int32_t h, int32_t pitch, const char *path) {
|
||||
if (!ctx || !data || !path || w <= 0 || h <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t *rgb = bufferToRgb(&ctx->display, data, w, h, pitch);
|
||||
|
||||
if (!rgb) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t result = stbi_write_png(path, w, h, 3, rgb, w * 3) ? 0 : -1;
|
||||
|
||||
free(rgb);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// dvxScreenshot
|
||||
// ============================================================
|
||||
|
|
|
|||
14
dvx/dvxApp.h
14
dvx/dvxApp.h
|
|
@ -199,6 +199,20 @@ void dvxTileWindowsH(AppContextT *ctx);
|
|||
// Vertical tile: stacked, full width, equal height.
|
||||
void dvxTileWindowsV(AppContextT *ctx);
|
||||
|
||||
// Load an image file (BMP, PNG, JPEG, GIF) and convert to the display's
|
||||
// native pixel format. Returns the pixel buffer on success (caller must
|
||||
// free with dvxFreeImage), or NULL on failure. Output params receive the
|
||||
// image dimensions and row pitch in bytes.
|
||||
uint8_t *dvxLoadImage(const AppContextT *ctx, const char *path, int32_t *outW, int32_t *outH, int32_t *outPitch);
|
||||
|
||||
// Free a pixel buffer returned by dvxLoadImage.
|
||||
void dvxFreeImage(uint8_t *data);
|
||||
|
||||
// Save native-format pixel data to a PNG file. The pixel data must be
|
||||
// in the display's native format (as returned by dvxLoadImage or
|
||||
// captured from a content buffer). Returns 0 on success, -1 on failure.
|
||||
int32_t dvxSaveImage(const AppContextT *ctx, const uint8_t *data, int32_t w, int32_t h, int32_t pitch, const char *path);
|
||||
|
||||
// Copy text to the process-wide clipboard buffer. The clipboard is a
|
||||
// simple static buffer (not inter-process) — adequate for copy/paste
|
||||
// within the DVX environment on single-tasking DOS.
|
||||
|
|
|
|||
|
|
@ -774,6 +774,10 @@ int32_t wgtSplitterGetPos(const WidgetT *w);
|
|||
// Takes ownership of the data buffer (freed on destroy).
|
||||
WidgetT *wgtImageButton(WidgetT *parent, uint8_t *data, int32_t w, int32_t h, int32_t pitch);
|
||||
|
||||
// Load an image button from a file (BMP, PNG, JPEG, GIF).
|
||||
// Returns NULL on load failure; falls through gracefully.
|
||||
WidgetT *wgtImageButtonFromFile(WidgetT *parent, const char *path);
|
||||
|
||||
// Replace the image data. Takes ownership of the new buffer.
|
||||
void wgtImageButtonSetData(WidgetT *w, uint8_t *data, int32_t imgW, int32_t imgH, int32_t pitch);
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,6 @@
|
|||
// widget-space coordinates to canvas-space by subtracting the border offset.
|
||||
|
||||
#include "widgetInternal.h"
|
||||
#include "../thirdparty/stb_image.h"
|
||||
#include "../thirdparty/stb_image_write.h"
|
||||
|
||||
#define CANVAS_BORDER 2
|
||||
|
||||
|
|
@ -34,7 +32,6 @@
|
|||
|
||||
static void canvasDrawDot(WidgetT *w, int32_t cx, int32_t cy);
|
||||
static void canvasDrawLine(WidgetT *w, int32_t x0, int32_t y0, int32_t x1, int32_t y1);
|
||||
static void canvasUnpackColor(const DisplayT *d, uint32_t pixel, uint8_t *r, uint8_t *g, uint8_t *b);
|
||||
|
||||
|
||||
// ============================================================
|
||||
|
|
@ -197,37 +194,6 @@ static void canvasDrawLine(WidgetT *w, int32_t x0, int32_t y0, int32_t x1, int32
|
|||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// canvasUnpackColor
|
||||
// ============================================================
|
||||
//
|
||||
// Reverse of packColor — extract RGB from a display-format pixel.
|
||||
// Only used during PNG save (wgtCanvasSave) to convert the canvas's
|
||||
// native-format pixels back to RGB for stb_image_write. The bit-shift
|
||||
// approach works for 15/16/24/32-bit modes; 8-bit paletted mode uses
|
||||
// a direct palette table lookup instead.
|
||||
|
||||
static void canvasUnpackColor(const DisplayT *d, uint32_t pixel, uint8_t *r, uint8_t *g, uint8_t *b) {
|
||||
if (d->format.bitsPerPixel == 8) {
|
||||
// 8-bit paletted — look up the palette entry
|
||||
int32_t idx = pixel & 0xFF;
|
||||
*r = d->palette[idx * 3 + 0];
|
||||
*g = d->palette[idx * 3 + 1];
|
||||
*b = d->palette[idx * 3 + 2];
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t rv = (pixel >> d->format.redShift) & ((1u << d->format.redBits) - 1);
|
||||
uint32_t gv = (pixel >> d->format.greenShift) & ((1u << d->format.greenBits) - 1);
|
||||
uint32_t bv = (pixel >> d->format.blueShift) & ((1u << d->format.blueBits) - 1);
|
||||
|
||||
// Scale back up to 8 bits
|
||||
*r = (uint8_t)(rv << (8 - d->format.redBits));
|
||||
*g = (uint8_t)(gv << (8 - d->format.greenBits));
|
||||
*b = (uint8_t)(bv << (8 - d->format.blueBits));
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// wgtCanvas
|
||||
// ============================================================
|
||||
|
|
@ -559,67 +525,35 @@ uint32_t wgtCanvasGetPixel(const WidgetT *w, int32_t x, int32_t y) {
|
|||
// ============================================================
|
||||
|
||||
// Load an image file into the canvas, replacing the current content.
|
||||
// Uses stb_image for decoding (supports BMP, PNG, JPEG, GIF, etc.).
|
||||
// The loaded RGB pixels are converted to the display's native pixel format
|
||||
// during load so that subsequent repaints are just a memcpy. The old buffer
|
||||
// is freed and replaced with the new one — canvas dimensions change to match
|
||||
// the loaded image.
|
||||
// Delegates to dvxLoadImage for format decoding and pixel conversion.
|
||||
// The old buffer is freed and replaced with the new one — canvas
|
||||
// dimensions change to match the loaded image.
|
||||
int32_t wgtCanvasLoad(WidgetT *w, const char *path) {
|
||||
if (!w || w->type != WidgetCanvasE || !path) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Find the AppContextT to get display format
|
||||
WidgetT *root = w;
|
||||
|
||||
while (root->parent) {
|
||||
root = root->parent;
|
||||
}
|
||||
|
||||
AppContextT *ctx = (AppContextT *)root->userData;
|
||||
AppContextT *ctx = wgtGetContext(w);
|
||||
|
||||
if (!ctx) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const DisplayT *d = &ctx->display;
|
||||
|
||||
int imgW;
|
||||
int imgH;
|
||||
int channels;
|
||||
uint8_t *rgb = stbi_load(path, &imgW, &imgH, &channels, 3);
|
||||
|
||||
if (!rgb) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t bpp = d->format.bytesPerPixel;
|
||||
int32_t pitch = imgW * bpp;
|
||||
uint8_t *data = (uint8_t *)malloc(pitch * imgH);
|
||||
int32_t imgW;
|
||||
int32_t imgH;
|
||||
int32_t pitch;
|
||||
uint8_t *data = dvxLoadImage(ctx, path, &imgW, &imgH, &pitch);
|
||||
|
||||
if (!data) {
|
||||
stbi_image_free(rgb);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int32_t y = 0; y < imgH; y++) {
|
||||
for (int32_t x = 0; x < imgW; x++) {
|
||||
const uint8_t *src = rgb + (y * imgW + x) * 3;
|
||||
uint32_t color = packColor(d, src[0], src[1], src[2]);
|
||||
uint8_t *dst = data + y * pitch + x * bpp;
|
||||
|
||||
canvasPutPixel(dst, color, bpp);
|
||||
}
|
||||
}
|
||||
|
||||
stbi_image_free(rgb);
|
||||
|
||||
free(w->as.canvas.data);
|
||||
w->as.canvas.data = data;
|
||||
w->as.canvas.canvasW = imgW;
|
||||
w->as.canvas.canvasH = imgH;
|
||||
w->as.canvas.canvasPitch = pitch;
|
||||
w->as.canvas.canvasBpp = bpp;
|
||||
w->as.canvas.canvasBpp = ctx->display.format.bytesPerPixel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -629,54 +563,20 @@ int32_t wgtCanvasLoad(WidgetT *w, const char *path) {
|
|||
// wgtCanvasSave
|
||||
// ============================================================
|
||||
|
||||
// Save the canvas content to a PNG file. Since the canvas stores pixels in
|
||||
// the display's native format (which varies per video mode), we must convert
|
||||
// back to RGB before writing. This is the inverse of the load conversion.
|
||||
// Save the canvas content to a PNG file. Delegates to dvxSaveImage
|
||||
// which handles native-to-RGB conversion and PNG encoding.
|
||||
int32_t wgtCanvasSave(WidgetT *w, const char *path) {
|
||||
if (!w || w->type != WidgetCanvasE || !path || !w->as.canvas.data) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Find the AppContextT to get display format
|
||||
WidgetT *root = w;
|
||||
|
||||
while (root->parent) {
|
||||
root = root->parent;
|
||||
}
|
||||
|
||||
AppContextT *ctx = (AppContextT *)root->userData;
|
||||
AppContextT *ctx = wgtGetContext(w);
|
||||
|
||||
if (!ctx) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const DisplayT *d = &ctx->display;
|
||||
int32_t cw = w->as.canvas.canvasW;
|
||||
int32_t ch = w->as.canvas.canvasH;
|
||||
int32_t bpp = d->format.bytesPerPixel;
|
||||
int32_t pitch = w->as.canvas.canvasPitch;
|
||||
|
||||
// Convert display format back to RGB
|
||||
uint8_t *rgb = (uint8_t *)malloc(cw * ch * 3);
|
||||
|
||||
if (!rgb) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int32_t y = 0; y < ch; y++) {
|
||||
for (int32_t x = 0; x < cw; x++) {
|
||||
const uint8_t *src = w->as.canvas.data + y * pitch + x * bpp;
|
||||
uint32_t pixel = canvasGetPixel(src, bpp);
|
||||
|
||||
uint8_t *dst = rgb + (y * cw + x) * 3;
|
||||
canvasUnpackColor(d, pixel, &dst[0], &dst[1], &dst[2]);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t result = stbi_write_png(path, cw, ch, 3, rgb, cw * 3);
|
||||
free(rgb);
|
||||
|
||||
return result ? 0 : -1;
|
||||
return dvxSaveImage(ctx, w->as.canvas.data, w->as.canvas.canvasW, w->as.canvas.canvasH, w->as.canvas.canvasPitch, path);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
// centering if the widget is larger than the image.
|
||||
|
||||
#include "widgetInternal.h"
|
||||
#include "../thirdparty/stb_image.h"
|
||||
|
||||
|
||||
// ============================================================
|
||||
|
|
@ -47,67 +46,28 @@ WidgetT *wgtImage(WidgetT *parent, uint8_t *data, int32_t w, int32_t h, int32_t
|
|||
// ============================================================
|
||||
//
|
||||
// Load an image from a file (BMP, PNG, JPEG, GIF), convert to
|
||||
// display pixel format, and create an image widget.
|
||||
|
||||
// Load an image from disk and create an Image widget. Uses stb_image for
|
||||
// decoding (any format it supports: PNG, BMP, JPEG, GIF, etc.). The RGB
|
||||
// pixels are converted to the display's native pixel format during load
|
||||
// using packColor, then the raw RGB data is freed. The per-pixel bpp switch
|
||||
// is duplicated here rather than using canvasPutPixel because this function
|
||||
// is in a different compilation unit and inlining across units isn't guaranteed
|
||||
// on DJGPP.
|
||||
// display pixel format, and create an image widget. Delegates to
|
||||
// dvxLoadImage for format decoding and pixel conversion.
|
||||
WidgetT *wgtImageFromFile(WidgetT *parent, const char *path) {
|
||||
if (!parent || !path) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Find the AppContextT to get display format
|
||||
AppContextT *ctx = wgtGetContext(parent);
|
||||
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const DisplayT *d = &ctx->display;
|
||||
|
||||
// Load image via stb_image (force RGB)
|
||||
int imgW;
|
||||
int imgH;
|
||||
int channels;
|
||||
uint8_t *rgb = stbi_load(path, &imgW, &imgH, &channels, 3);
|
||||
|
||||
if (!rgb) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Convert RGB to display pixel format
|
||||
int32_t bpp = d->format.bytesPerPixel;
|
||||
int32_t pitch = imgW * bpp;
|
||||
uint8_t *buf = (uint8_t *)malloc(pitch * imgH);
|
||||
int32_t imgW;
|
||||
int32_t imgH;
|
||||
int32_t pitch;
|
||||
uint8_t *buf = dvxLoadImage(ctx, path, &imgW, &imgH, &pitch);
|
||||
|
||||
if (!buf) {
|
||||
stbi_image_free(rgb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (int32_t y = 0; y < imgH; y++) {
|
||||
for (int32_t x = 0; x < imgW; x++) {
|
||||
const uint8_t *src = rgb + (y * imgW + x) * 3;
|
||||
uint32_t color = packColor(d, src[0], src[1], src[2]);
|
||||
uint8_t *dst = buf + y * pitch + x * bpp;
|
||||
|
||||
if (bpp == 1) {
|
||||
*dst = (uint8_t)color;
|
||||
} else if (bpp == 2) {
|
||||
*(uint16_t *)dst = (uint16_t)color;
|
||||
} else {
|
||||
*(uint32_t *)dst = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stbi_image_free(rgb);
|
||||
|
||||
return wgtImage(parent, buf, imgW, imgH, pitch);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,37 @@ WidgetT *wgtImageButton(WidgetT *parent, uint8_t *data, int32_t w, int32_t h, in
|
|||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// wgtImageButtonFromFile
|
||||
// ============================================================
|
||||
//
|
||||
// Load an image from disk and create an ImageButton widget.
|
||||
// Delegates to dvxLoadImage for format decoding and pixel conversion.
|
||||
|
||||
WidgetT *wgtImageButtonFromFile(WidgetT *parent, const char *path) {
|
||||
if (!parent || !path) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AppContextT *ctx = wgtGetContext(parent);
|
||||
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t imgW;
|
||||
int32_t imgH;
|
||||
int32_t pitch;
|
||||
uint8_t *buf = dvxLoadImage(ctx, path, &imgW, &imgH, &pitch);
|
||||
|
||||
if (!buf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return wgtImageButton(parent, buf, imgW, imgH, pitch);
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// wgtImageButtonSetData
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -159,6 +159,9 @@ DXE_EXPORT_TABLE(shellExportTable)
|
|||
DXE_EXPORT(dvxGetDisplay)
|
||||
DXE_EXPORT(dvxGetBlitOps)
|
||||
DXE_EXPORT(dvxSetWindowIcon)
|
||||
DXE_EXPORT(dvxLoadImage)
|
||||
DXE_EXPORT(dvxFreeImage)
|
||||
DXE_EXPORT(dvxSaveImage)
|
||||
DXE_EXPORT(dvxScreenshot)
|
||||
DXE_EXPORT(dvxWindowScreenshot)
|
||||
DXE_EXPORT(dvxCreateAccelTable)
|
||||
|
|
@ -311,6 +314,7 @@ DXE_EXPORT_TABLE(shellExportTable)
|
|||
|
||||
// dvxWidget.h — image / image button
|
||||
DXE_EXPORT(wgtImageButton)
|
||||
DXE_EXPORT(wgtImageButtonFromFile)
|
||||
DXE_EXPORT(wgtImageButtonSetData)
|
||||
DXE_EXPORT(wgtImage)
|
||||
DXE_EXPORT(wgtImageFromFile)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue