More code cleanup.
This commit is contained in:
parent
78302c26d2
commit
1556ba889c
28 changed files with 459 additions and 449 deletions
27
Makefile
Normal file
27
Makefile
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# DVX GUI — Top-level Makefile
|
||||
#
|
||||
# Builds the full DVX stack: library, task switcher, shell, and apps.
|
||||
|
||||
.PHONY: all clean dvx tasks dvxshell apps
|
||||
|
||||
all: dvx tasks dvxshell apps
|
||||
|
||||
dvx:
|
||||
$(MAKE) -C dvx
|
||||
|
||||
tasks:
|
||||
$(MAKE) -C tasks
|
||||
|
||||
dvxshell: dvx tasks
|
||||
$(MAKE) -C dvxshell
|
||||
|
||||
apps: dvx tasks dvxshell
|
||||
$(MAKE) -C apps
|
||||
|
||||
clean:
|
||||
$(MAKE) -C dvx clean
|
||||
$(MAKE) -C tasks clean
|
||||
$(MAKE) -C dvxshell clean
|
||||
$(MAKE) -C apps clean
|
||||
-rmdir obj/dvx/widgets obj/dvx/platform obj/dvx obj/tasks obj/dvxshell obj/apps obj 2>/dev/null
|
||||
-rmdir bin/apps/progman bin/apps/notepad bin/apps/clock bin/apps/dvxdemo bin/apps bin lib 2>/dev/null
|
||||
|
|
@ -10,25 +10,32 @@ OBJDIR = ../obj/apps
|
|||
BINDIR = ../bin/apps
|
||||
|
||||
# App definitions: each is a subdir with a single .c file
|
||||
APPS = progman notepad clock
|
||||
APPS = progman notepad clock dvxdemo
|
||||
|
||||
.PHONY: all clean $(APPS)
|
||||
|
||||
all: $(APPS)
|
||||
|
||||
progman: $(BINDIR)/progman.app
|
||||
notepad: $(BINDIR)/notepad.app
|
||||
clock: $(BINDIR)/clock.app
|
||||
progman: $(BINDIR)/progman/progman.app
|
||||
notepad: $(BINDIR)/notepad/notepad.app
|
||||
clock: $(BINDIR)/clock/clock.app
|
||||
dvxdemo: $(BINDIR)/dvxdemo/dvxdemo.app
|
||||
|
||||
$(BINDIR)/progman.app: $(OBJDIR)/progman.o | $(BINDIR)
|
||||
$(BINDIR)/progman/progman.app: $(OBJDIR)/progman.o | $(BINDIR)/progman
|
||||
$(DXE3GEN) -o $@ -E _appDescriptor -E _appMain -U $<
|
||||
|
||||
$(BINDIR)/notepad.app: $(OBJDIR)/notepad.o | $(BINDIR)
|
||||
$(BINDIR)/notepad/notepad.app: $(OBJDIR)/notepad.o | $(BINDIR)/notepad
|
||||
$(DXE3GEN) -o $@ -E _appDescriptor -E _appMain -U $<
|
||||
|
||||
$(BINDIR)/clock.app: $(OBJDIR)/clock.o | $(BINDIR)
|
||||
$(BINDIR)/clock/clock.app: $(OBJDIR)/clock.o | $(BINDIR)/clock
|
||||
$(DXE3GEN) -o $@ -E _appDescriptor -E _appMain -E _appShutdown -U $<
|
||||
|
||||
DVXDEMO_BMPS = logo.bmp new.bmp open.bmp sample.bmp save.bmp
|
||||
|
||||
$(BINDIR)/dvxdemo/dvxdemo.app: $(OBJDIR)/dvxdemo.o $(addprefix dvxdemo/,$(DVXDEMO_BMPS)) | $(BINDIR)/dvxdemo
|
||||
$(DXE3GEN) -o $@ -E _appDescriptor -E _appMain -U $<
|
||||
cp $(addprefix dvxdemo/,$(DVXDEMO_BMPS)) $(BINDIR)/dvxdemo/
|
||||
|
||||
$(OBJDIR)/progman.o: progman/progman.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
|
|
@ -38,16 +45,33 @@ $(OBJDIR)/notepad.o: notepad/notepad.c | $(OBJDIR)
|
|||
$(OBJDIR)/clock.o: clock/clock.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/dvxdemo.o: dvxdemo/dvxdemo.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir -p $(OBJDIR)
|
||||
|
||||
$(BINDIR):
|
||||
mkdir -p $(BINDIR)
|
||||
$(BINDIR)/progman:
|
||||
mkdir -p $(BINDIR)/progman
|
||||
|
||||
$(BINDIR)/notepad:
|
||||
mkdir -p $(BINDIR)/notepad
|
||||
|
||||
$(BINDIR)/clock:
|
||||
mkdir -p $(BINDIR)/clock
|
||||
|
||||
$(BINDIR)/dvxdemo:
|
||||
mkdir -p $(BINDIR)/dvxdemo
|
||||
|
||||
# Dependencies
|
||||
$(OBJDIR)/progman.o: progman/progman.c ../dvx/dvxApp.h ../dvx/dvxDialog.h ../dvx/dvxWidget.h ../dvx/dvxWm.h ../dvxshell/shellApp.h
|
||||
$(OBJDIR)/notepad.o: notepad/notepad.c ../dvx/dvxApp.h ../dvx/dvxDialog.h ../dvx/dvxWidget.h ../dvx/dvxWm.h ../dvxshell/shellApp.h
|
||||
$(OBJDIR)/clock.o: clock/clock.c ../dvx/dvxApp.h ../dvx/dvxWidget.h ../dvx/dvxDraw.h ../dvx/dvxVideo.h ../dvxshell/shellApp.h ../tasks/taskswitch.h
|
||||
$(OBJDIR)/dvxdemo.o: dvxdemo/dvxdemo.c ../dvx/dvxApp.h ../dvx/dvxDialog.h ../dvx/dvxWidget.h ../dvx/dvxWm.h ../dvx/dvxVideo.h ../dvxshell/shellApp.h
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR) $(BINDIR)
|
||||
rm -f $(OBJDIR)/progman.o $(OBJDIR)/notepad.o $(OBJDIR)/clock.o $(OBJDIR)/dvxdemo.o
|
||||
rm -f $(BINDIR)/progman/progman.app
|
||||
rm -f $(BINDIR)/notepad/notepad.app
|
||||
rm -f $(BINDIR)/clock/clock.app
|
||||
rm -f $(BINDIR)/dvxdemo/dvxdemo.app $(addprefix $(BINDIR)/dvxdemo/,$(DVXDEMO_BMPS))
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
// demo.c — DVX GUI demonstration application
|
||||
// dvxdemo.c — DVX GUI demonstration app (DXE version)
|
||||
//
|
||||
// Callback-only app that opens several windows showcasing the DVX
|
||||
// widget system, paint callbacks, menus, accelerators, etc.
|
||||
|
||||
#include "dvxApp.h"
|
||||
#include "dvxDialog.h"
|
||||
#include "dvxWidget.h"
|
||||
#include "dvxWm.h"
|
||||
#include "shellApp.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "thirdparty/stb_image.h"
|
||||
|
||||
// ============================================================
|
||||
// Menu command IDs
|
||||
|
|
@ -49,7 +53,8 @@
|
|||
// Prototypes
|
||||
// ============================================================
|
||||
|
||||
static uint8_t *loadBmpPixels(AppContextT *ctx, const char *path, int32_t *outW, int32_t *outH, int32_t *outPitch);
|
||||
int32_t appMain(DxeAppContextT *ctx);
|
||||
static void onCanvasDraw(WidgetT *w, int32_t cx, int32_t cy, bool drag);
|
||||
static void onCloseCb(WindowT *win);
|
||||
static void onCloseMainCb(WindowT *win);
|
||||
static void onMenuCb(WindowT *win, int32_t menuId);
|
||||
|
|
@ -58,102 +63,58 @@ static void onPaintColor(WindowT *win, RectT *dirtyArea);
|
|||
static void onPaintPattern(WindowT *win, RectT *dirtyArea);
|
||||
static void onPaintText(WindowT *win, RectT *dirtyArea);
|
||||
static void onToolbarClick(WidgetT *w);
|
||||
static void setupControlsWindow(AppContextT *ctx);
|
||||
static void setupMainWindow(AppContextT *ctx);
|
||||
static void setupTerminalWindow(AppContextT *ctx);
|
||||
static void setupWidgetDemo(AppContextT *ctx);
|
||||
static void setupControlsWindow(void);
|
||||
static void setupMainWindow(void);
|
||||
static void setupTerminalWindow(void);
|
||||
static void setupWidgetDemo(void);
|
||||
|
||||
// ============================================================
|
||||
// Globals
|
||||
// Module state
|
||||
// ============================================================
|
||||
|
||||
static AppContextT *sCtx = NULL;
|
||||
|
||||
static AppContextT *sAc = NULL;
|
||||
static DxeAppContextT *sDxeCtx = NULL;
|
||||
|
||||
// ============================================================
|
||||
// loadBmpPixels — load a BMP/PNG file into display-format pixels
|
||||
// App descriptor
|
||||
// ============================================================
|
||||
|
||||
static uint8_t *loadBmpPixels(AppContextT *ctx, const char *path, int32_t *outW, int32_t *outH, int32_t *outPitch) {
|
||||
int imgW;
|
||||
int imgH;
|
||||
int channels;
|
||||
uint8_t *rgb = stbi_load(path, &imgW, &imgH, &channels, 3);
|
||||
AppDescriptorT appDescriptor = {
|
||||
.name = "DVX Demo",
|
||||
.hasMainLoop = false,
|
||||
.stackSize = 0,
|
||||
.priority = TS_PRIORITY_NORMAL
|
||||
};
|
||||
|
||||
if (!rgb) {
|
||||
return NULL;
|
||||
}
|
||||
// ============================================================
|
||||
// Callbacks
|
||||
// ============================================================
|
||||
|
||||
const DisplayT *d = dvxGetDisplay(ctx);
|
||||
int32_t bpp = d->format.bytesPerPixel;
|
||||
int32_t pitch = imgW * bpp;
|
||||
uint8_t *data = (uint8_t *)malloc(pitch * imgH);
|
||||
|
||||
if (!data) {
|
||||
stbi_image_free(rgb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (int32_t y = 0; y < imgH; y++) {
|
||||
for (int32_t x = 0; x < imgW; x++) {
|
||||
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;
|
||||
|
||||
if (bpp == 1) {
|
||||
*dst = (uint8_t)color;
|
||||
} else if (bpp == 2) {
|
||||
*(uint16_t *)dst = (uint16_t)color;
|
||||
static void onCanvasDraw(WidgetT *w, int32_t cx, int32_t cy, bool drag) {
|
||||
if (drag && w->as.canvas.lastX >= 0) {
|
||||
wgtCanvasDrawLine(w, w->as.canvas.lastX, w->as.canvas.lastY, cx, cy);
|
||||
} else {
|
||||
*(uint32_t *)dst = color;
|
||||
}
|
||||
wgtCanvasDrawLine(w, cx, cy, cx, cy);
|
||||
}
|
||||
}
|
||||
|
||||
stbi_image_free(rgb);
|
||||
*outW = imgW;
|
||||
*outH = imgH;
|
||||
*outPitch = pitch;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// onCloseCb
|
||||
// ============================================================
|
||||
|
||||
static void onCloseCb(WindowT *win) {
|
||||
AppContextT *ctx = (AppContextT *)win->userData;
|
||||
|
||||
if (ctx) {
|
||||
dvxDestroyWindow(ctx, win);
|
||||
}
|
||||
dvxDestroyWindow(sAc, win);
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// onCloseMainCb
|
||||
// ============================================================
|
||||
|
||||
static void onCloseMainCb(WindowT *win) {
|
||||
AppContextT *ctx = (AppContextT *)win->userData;
|
||||
|
||||
if (ctx) {
|
||||
int32_t result = dvxMessageBox(ctx, "Exit",
|
||||
"Are you sure you want to exit?",
|
||||
int32_t result = dvxMessageBox(sAc, "Close",
|
||||
"Close this window?",
|
||||
MB_YESNO | MB_ICONQUESTION);
|
||||
|
||||
if (result == ID_YES) {
|
||||
dvxQuit(ctx);
|
||||
}
|
||||
dvxDestroyWindow(sAc, win);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// onMenuCb
|
||||
// ============================================================
|
||||
|
||||
static const FileFilterT sFileFilters[] = {
|
||||
{"All Files (*.*)", "*.*"},
|
||||
{"Text Files (*.txt)", "*.txt"},
|
||||
|
|
@ -163,16 +124,14 @@ static const FileFilterT sFileFilters[] = {
|
|||
};
|
||||
|
||||
static void onMenuCb(WindowT *win, int32_t menuId) {
|
||||
AppContextT *ctx = (AppContextT *)win->userData;
|
||||
|
||||
switch (menuId) {
|
||||
case CMD_FILE_OPEN: {
|
||||
char path[260];
|
||||
|
||||
if (dvxFileDialog(ctx, "Open File", FD_OPEN, NULL, sFileFilters, 5, path, sizeof(path))) {
|
||||
if (dvxFileDialog(sAc, "Open File", FD_OPEN, NULL, sFileFilters, 5, path, sizeof(path))) {
|
||||
char msg[300];
|
||||
snprintf(msg, sizeof(msg), "Selected: %s", path);
|
||||
dvxMessageBox(ctx, "Open", msg, MB_OK | MB_ICONINFO);
|
||||
dvxMessageBox(sAc, "Open", msg, MB_OK | MB_ICONINFO);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -181,96 +140,84 @@ static void onMenuCb(WindowT *win, int32_t menuId) {
|
|||
case CMD_FILE_SAVE: {
|
||||
char path[260];
|
||||
|
||||
if (dvxFileDialog(ctx, "Save As", FD_SAVE, NULL, sFileFilters, 5, path, sizeof(path))) {
|
||||
if (dvxFileDialog(sAc, "Save As", FD_SAVE, NULL, sFileFilters, 5, path, sizeof(path))) {
|
||||
char msg[300];
|
||||
snprintf(msg, sizeof(msg), "Save to: %s", path);
|
||||
dvxMessageBox(ctx, "Save", msg, MB_OK | MB_ICONINFO);
|
||||
dvxMessageBox(sAc, "Save", msg, MB_OK | MB_ICONINFO);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_FILE_EXIT:
|
||||
if (ctx) {
|
||||
int32_t result = dvxMessageBox(ctx, "Exit",
|
||||
"Are you sure you want to exit?",
|
||||
MB_YESNO | MB_ICONQUESTION);
|
||||
|
||||
if (result == ID_YES) {
|
||||
dvxQuit(ctx);
|
||||
}
|
||||
}
|
||||
onCloseMainCb(win);
|
||||
break;
|
||||
|
||||
case CMD_VIEW_TERM:
|
||||
setupTerminalWindow(ctx);
|
||||
setupTerminalWindow();
|
||||
break;
|
||||
|
||||
case CMD_VIEW_CTRL:
|
||||
setupControlsWindow(ctx);
|
||||
setupControlsWindow();
|
||||
break;
|
||||
|
||||
case CMD_VIEW_DEBUG_LYT: {
|
||||
static bool sDebugLyt = false;
|
||||
sDebugLyt = !sDebugLyt;
|
||||
wgtSetDebugLayout(ctx, sDebugLyt);
|
||||
wgtSetDebugLayout(sAc, sDebugLyt);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_WIN_CASCADE:
|
||||
dvxCascadeWindows(ctx);
|
||||
dvxCascadeWindows(sAc);
|
||||
break;
|
||||
|
||||
case CMD_WIN_TILE_H:
|
||||
dvxTileWindowsH(ctx);
|
||||
dvxTileWindowsH(sAc);
|
||||
break;
|
||||
|
||||
case CMD_WIN_TILE_V:
|
||||
dvxTileWindowsV(ctx);
|
||||
dvxTileWindowsV(sAc);
|
||||
break;
|
||||
|
||||
case CMD_WIN_TILE:
|
||||
dvxTileWindows(ctx);
|
||||
dvxTileWindows(sAc);
|
||||
break;
|
||||
|
||||
case CMD_HELP_ABOUT:
|
||||
dvxMessageBox(sCtx, "About DVX Demo",
|
||||
dvxMessageBox(sAc, "About DVX Demo",
|
||||
"DVX GUI Demonstration\n\n"
|
||||
"A DOS Visual eXecutive windowing system for DOS.",
|
||||
MB_OK | MB_ICONINFO);
|
||||
break;
|
||||
|
||||
case CMD_CTX_CUT:
|
||||
dvxMessageBox(ctx, "Context Menu", "Cut selected.", MB_OK | MB_ICONINFO);
|
||||
dvxMessageBox(sAc, "Context Menu", "Cut selected.", MB_OK | MB_ICONINFO);
|
||||
break;
|
||||
|
||||
case CMD_CTX_COPY:
|
||||
dvxMessageBox(ctx, "Context Menu", "Copied to clipboard.", MB_OK | MB_ICONINFO);
|
||||
dvxMessageBox(sAc, "Context Menu", "Copied to clipboard.", MB_OK | MB_ICONINFO);
|
||||
break;
|
||||
|
||||
case CMD_CTX_PASTE:
|
||||
dvxMessageBox(ctx, "Context Menu", "Pasted from clipboard.", MB_OK | MB_ICONINFO);
|
||||
dvxMessageBox(sAc, "Context Menu", "Pasted from clipboard.", MB_OK | MB_ICONINFO);
|
||||
break;
|
||||
|
||||
case CMD_CTX_DELETE:
|
||||
dvxMessageBox(ctx, "Context Menu", "Deleted.", MB_OK | MB_ICONINFO);
|
||||
dvxMessageBox(sAc, "Context Menu", "Deleted.", MB_OK | MB_ICONINFO);
|
||||
break;
|
||||
|
||||
case CMD_CTX_SELALL:
|
||||
dvxMessageBox(ctx, "Context Menu", "Selected all.", MB_OK | MB_ICONINFO);
|
||||
dvxMessageBox(sAc, "Context Menu", "Selected all.", MB_OK | MB_ICONINFO);
|
||||
break;
|
||||
|
||||
case CMD_CTX_PROPS:
|
||||
dvxMessageBox(ctx, "Properties", "Window properties dialog would appear here.", MB_OK | MB_ICONINFO);
|
||||
dvxMessageBox(sAc, "Properties", "Window properties dialog would appear here.", MB_OK | MB_ICONINFO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// onOkClick
|
||||
// ============================================================
|
||||
|
||||
static void onOkClick(WidgetT *w) {
|
||||
WidgetT *root = w;
|
||||
|
||||
|
|
@ -286,20 +233,15 @@ static void onOkClick(WidgetT *w) {
|
|||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// onPaintColor
|
||||
// ============================================================
|
||||
|
||||
static void onPaintColor(WindowT *win, RectT *dirtyArea) {
|
||||
(void)dirtyArea;
|
||||
AppContextT *ctx = (AppContextT *)win->userData;
|
||||
|
||||
if (!win->contentBuf || !ctx) {
|
||||
if (!win->contentBuf || !sAc) {
|
||||
return;
|
||||
}
|
||||
|
||||
const DisplayT *d = dvxGetDisplay(ctx);
|
||||
const BlitOpsT *ops = dvxGetBlitOps(ctx);
|
||||
const DisplayT *d = dvxGetDisplay(sAc);
|
||||
const BlitOpsT *ops = dvxGetBlitOps(sAc);
|
||||
|
||||
for (int32_t y = 0; y < win->contentH; y++) {
|
||||
uint8_t r = (uint8_t)((y * 255) / (win->contentH > 1 ? win->contentH - 1 : 1));
|
||||
|
|
@ -314,19 +256,14 @@ static void onPaintColor(WindowT *win, RectT *dirtyArea) {
|
|||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// onPaintPattern
|
||||
// ============================================================
|
||||
|
||||
static void onPaintPattern(WindowT *win, RectT *dirtyArea) {
|
||||
(void)dirtyArea;
|
||||
AppContextT *ctx = (AppContextT *)win->userData;
|
||||
|
||||
if (!win->contentBuf || !ctx) {
|
||||
if (!win->contentBuf || !sAc) {
|
||||
return;
|
||||
}
|
||||
|
||||
const DisplayT *d = dvxGetDisplay(ctx);
|
||||
const DisplayT *d = dvxGetDisplay(sAc);
|
||||
int32_t bpp = d->format.bytesPerPixel;
|
||||
int32_t sq = 16;
|
||||
|
||||
|
|
@ -350,21 +287,16 @@ static void onPaintPattern(WindowT *win, RectT *dirtyArea) {
|
|||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// onPaintText
|
||||
// ============================================================
|
||||
|
||||
static void onPaintText(WindowT *win, RectT *dirtyArea) {
|
||||
(void)dirtyArea;
|
||||
AppContextT *ctx = (AppContextT *)win->userData;
|
||||
|
||||
if (!win->contentBuf || !ctx) {
|
||||
if (!win->contentBuf || !sAc) {
|
||||
return;
|
||||
}
|
||||
|
||||
const DisplayT *d = dvxGetDisplay(ctx);
|
||||
const BlitOpsT *ops = dvxGetBlitOps(ctx);
|
||||
const BitmapFontT *font = dvxGetFont(ctx);
|
||||
const DisplayT *d = dvxGetDisplay(sAc);
|
||||
const BlitOpsT *ops = dvxGetBlitOps(sAc);
|
||||
const BitmapFontT *font = dvxGetFont(sAc);
|
||||
int32_t bpp = d->format.bytesPerPixel;
|
||||
|
||||
uint32_t bg = packColor(d, 255, 255, 255);
|
||||
|
|
@ -447,10 +379,6 @@ static void onPaintText(WindowT *win, RectT *dirtyArea) {
|
|||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// onToolbarClick
|
||||
// ============================================================
|
||||
|
||||
static void onToolbarClick(WidgetT *w) {
|
||||
WidgetT *root = w;
|
||||
|
||||
|
|
@ -473,17 +401,16 @@ static void onToolbarClick(WidgetT *w) {
|
|||
static const char *colorItems[] = {"Red", "Green", "Blue", "Yellow", "Cyan", "Magenta"};
|
||||
static const char *sizeItems[] = {"Small", "Medium", "Large", "Extra Large"};
|
||||
|
||||
static void setupControlsWindow(AppContextT *ctx) {
|
||||
WindowT *win = dvxCreateWindow(ctx, "Advanced Widgets", 380, 50, 360, 440, true);
|
||||
static void setupControlsWindow(void) {
|
||||
WindowT *win = dvxCreateWindow(sAc, "Advanced Widgets", 380, 50, 360, 440, true);
|
||||
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
|
||||
win->userData = ctx;
|
||||
win->onClose = onCloseCb;
|
||||
|
||||
WidgetT *root = wgtInitWindow(ctx, win);
|
||||
WidgetT *root = wgtInitWindow(sAc, win);
|
||||
|
||||
// TabControl at top
|
||||
WidgetT *tabs = wgtTabControl(root);
|
||||
|
|
@ -617,58 +544,35 @@ static void setupControlsWindow(AppContextT *ctx) {
|
|||
wgtLabel(sp, "Bottom of scroll area");
|
||||
wgtButton(sp, "Scrolled &Button");
|
||||
|
||||
// --- Tab 5: Toolbar (ImageButtons + VSeparator) ---
|
||||
// --- Tab 5: Toolbar (text buttons + VSeparator) ---
|
||||
WidgetT *page5tb = wgtTabPage(tabs, "Tool&bar");
|
||||
|
||||
WidgetT *tb = wgtToolbar(page5tb);
|
||||
|
||||
int32_t imgW;
|
||||
int32_t imgH;
|
||||
int32_t imgPitch;
|
||||
|
||||
uint8_t *newData = loadBmpPixels(ctx, "new.bmp", &imgW, &imgH, &imgPitch);
|
||||
if (newData) {
|
||||
WidgetT *btnNew = wgtImageButton(tb, newData, imgW, imgH, imgPitch);
|
||||
wgtSetName(btnNew, "New");
|
||||
WidgetT *btnNew = wgtButton(tb, "&New");
|
||||
btnNew->onClick = onToolbarClick;
|
||||
}
|
||||
|
||||
uint8_t *openData = loadBmpPixels(ctx, "open.bmp", &imgW, &imgH, &imgPitch);
|
||||
if (openData) {
|
||||
WidgetT *btnOpen = wgtImageButton(tb, openData, imgW, imgH, imgPitch);
|
||||
wgtSetName(btnOpen, "Open");
|
||||
WidgetT *btnOpen = wgtButton(tb, "&Open");
|
||||
btnOpen->onClick = onToolbarClick;
|
||||
}
|
||||
|
||||
uint8_t *saveData = loadBmpPixels(ctx, "save.bmp", &imgW, &imgH, &imgPitch);
|
||||
if (saveData) {
|
||||
WidgetT *btnSave = wgtImageButton(tb, saveData, imgW, imgH, imgPitch);
|
||||
wgtSetName(btnSave, "Save");
|
||||
WidgetT *btnSave = wgtButton(tb, "&Save");
|
||||
btnSave->onClick = onToolbarClick;
|
||||
}
|
||||
|
||||
wgtVSeparator(tb);
|
||||
WidgetT *btnHelp = wgtButton(tb, "&Help");
|
||||
btnHelp->onClick = onToolbarClick;
|
||||
|
||||
wgtLabel(page5tb, "ImageButtons with VSeparator.");
|
||||
wgtLabel(page5tb, "Toolbar with text buttons and VSeparator.");
|
||||
|
||||
// --- Tab 6: Media (Image, ImageFromFile) ---
|
||||
// --- Tab 6: Media (Image from file) ---
|
||||
WidgetT *page6m = wgtTabPage(tabs, "&Media");
|
||||
|
||||
char samplePath[272];
|
||||
snprintf(samplePath, sizeof(samplePath), "%s/sample.bmp", sDxeCtx->appDir);
|
||||
wgtLabel(page6m, "ImageFromFile (sample.bmp):");
|
||||
wgtImageFromFile(page6m, "sample.bmp");
|
||||
WidgetT *img = wgtImageFromFile(page6m, samplePath);
|
||||
|
||||
wgtHSeparator(page6m);
|
||||
|
||||
wgtLabel(page6m, "Image (logo.bmp):");
|
||||
WidgetT *imgRow = wgtHBox(page6m);
|
||||
uint8_t *logoData = loadBmpPixels(ctx, "logo.bmp", &imgW, &imgH, &imgPitch);
|
||||
if (logoData) {
|
||||
wgtImage(imgRow, logoData, imgW, imgH, imgPitch);
|
||||
if (!img) {
|
||||
wgtLabel(page6m, "(File not found)");
|
||||
}
|
||||
wgtVSeparator(imgRow);
|
||||
wgtLabel(imgRow, "32x32 DVX logo");
|
||||
|
||||
// --- Tab 7: Editor (TextArea, Canvas) ---
|
||||
WidgetT *page7e = wgtTabPage(tabs, "&Editor");
|
||||
|
|
@ -681,7 +585,7 @@ static void setupControlsWindow(AppContextT *ctx) {
|
|||
wgtHSeparator(page7e);
|
||||
|
||||
wgtLabel(page7e, "Canvas (draw with mouse):");
|
||||
const DisplayT *d = dvxGetDisplay(ctx);
|
||||
const DisplayT *d = dvxGetDisplay(sAc);
|
||||
WidgetT *cv = wgtCanvas(page7e, 280, 80);
|
||||
wgtCanvasSetPenColor(cv, packColor(d, 200, 0, 0));
|
||||
wgtCanvasDrawRect(cv, 5, 5, 50, 35);
|
||||
|
|
@ -690,6 +594,7 @@ static void setupControlsWindow(AppContextT *ctx) {
|
|||
wgtCanvasSetPenColor(cv, packColor(d, 0, 150, 0));
|
||||
wgtCanvasDrawLine(cv, 70, 5, 130, 70);
|
||||
wgtCanvasSetPenColor(cv, packColor(d, 0, 0, 0));
|
||||
wgtCanvasSetMouseCallback(cv, onCanvasDraw);
|
||||
|
||||
// --- Tab 8: Splitter ---
|
||||
WidgetT *page8s = wgtTabPage(tabs, "S&plit");
|
||||
|
|
@ -831,12 +736,11 @@ static void setupControlsWindow(AppContextT *ctx) {
|
|||
// setupMainWindow — info window + paint demos
|
||||
// ============================================================
|
||||
|
||||
static void setupMainWindow(AppContextT *ctx) {
|
||||
static void setupMainWindow(void) {
|
||||
// Window 1: Text information window with menu bar
|
||||
WindowT *win1 = dvxCreateWindow(ctx, "DVX Information", 50, 40, 340, 350, true);
|
||||
WindowT *win1 = dvxCreateWindow(sAc, "DVX Information", 50, 40, 340, 350, true);
|
||||
|
||||
if (win1) {
|
||||
win1->userData = ctx;
|
||||
win1->onPaint = onPaintText;
|
||||
win1->onClose = onCloseMainCb;
|
||||
win1->onMenu = onMenuCb;
|
||||
|
|
@ -924,17 +828,16 @@ static void setupMainWindow(AppContextT *ctx) {
|
|||
win1->contextMenu = winCtx;
|
||||
|
||||
wmUpdateContentRect(win1);
|
||||
wmReallocContentBuf(win1, &ctx->display);
|
||||
wmReallocContentBuf(win1, &sAc->display);
|
||||
|
||||
RectT fullRect = {0, 0, win1->contentW, win1->contentH};
|
||||
win1->onPaint(win1, &fullRect);
|
||||
}
|
||||
|
||||
// Window 2: Color gradient
|
||||
WindowT *win2 = dvxCreateWindow(ctx, "Color Gradient", 200, 100, 280, 250, true);
|
||||
WindowT *win2 = dvxCreateWindow(sAc, "Color Gradient", 200, 100, 280, 250, true);
|
||||
|
||||
if (win2) {
|
||||
win2->userData = ctx;
|
||||
win2->onPaint = onPaintColor;
|
||||
win2->onClose = onCloseCb;
|
||||
|
||||
|
|
@ -943,17 +846,16 @@ static void setupMainWindow(AppContextT *ctx) {
|
|||
}
|
||||
|
||||
// Window 3: Checkerboard pattern with scrollbars
|
||||
WindowT *win3 = dvxCreateWindow(ctx, "Pattern", 400, 150, 250, 220, true);
|
||||
WindowT *win3 = dvxCreateWindow(sAc, "Pattern", 400, 150, 250, 220, true);
|
||||
|
||||
if (win3) {
|
||||
win3->userData = ctx;
|
||||
win3->onPaint = onPaintPattern;
|
||||
win3->onClose = onCloseCb;
|
||||
|
||||
wmAddVScrollbar(win3, 0, 100, 25);
|
||||
wmAddHScrollbar(win3, 0, 100, 25);
|
||||
wmUpdateContentRect(win3);
|
||||
wmReallocContentBuf(win3, &ctx->display);
|
||||
wmReallocContentBuf(win3, &sAc->display);
|
||||
|
||||
RectT fullRect = {0, 0, win3->contentW, win3->contentH};
|
||||
win3->onPaint(win3, &fullRect);
|
||||
|
|
@ -965,17 +867,16 @@ static void setupMainWindow(AppContextT *ctx) {
|
|||
// setupTerminalWindow — ANSI terminal widget demo
|
||||
// ============================================================
|
||||
|
||||
static void setupTerminalWindow(AppContextT *ctx) {
|
||||
WindowT *win = dvxCreateWindow(ctx, "ANSI Terminal", 60, 60, 660, 420, true);
|
||||
static void setupTerminalWindow(void) {
|
||||
WindowT *win = dvxCreateWindow(sAc, "ANSI Terminal", 60, 60, 660, 420, true);
|
||||
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
|
||||
win->userData = ctx;
|
||||
win->onClose = onCloseCb;
|
||||
|
||||
WidgetT *root = wgtInitWindow(ctx, win);
|
||||
WidgetT *root = wgtInitWindow(sAc, win);
|
||||
WidgetT *term = wgtAnsiTerm(root, 80, 25);
|
||||
|
||||
term->weight = 100;
|
||||
|
|
@ -1036,8 +937,8 @@ static void setupTerminalWindow(AppContextT *ctx) {
|
|||
WidgetT *sb = wgtStatusBar(root);
|
||||
wgtLabel(sb, "80x25 [Local]");
|
||||
|
||||
dvxFitWindow(ctx, win);
|
||||
dvxMinimizeWindow(ctx, win);
|
||||
dvxFitWindow(sAc, win);
|
||||
dvxMinimizeWindow(sAc, win);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1045,18 +946,17 @@ static void setupTerminalWindow(AppContextT *ctx) {
|
|||
// setupWidgetDemo — form with accelerators
|
||||
// ============================================================
|
||||
|
||||
static void setupWidgetDemo(AppContextT *ctx) {
|
||||
WindowT *win = dvxCreateWindow(ctx, "Widget Demo", 80, 200, 280, 360, true);
|
||||
static void setupWidgetDemo(void) {
|
||||
WindowT *win = dvxCreateWindow(sAc, "Widget Demo", 80, 200, 280, 360, true);
|
||||
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
|
||||
win->userData = ctx;
|
||||
win->onClose = onCloseCb;
|
||||
win->onMenu = onMenuCb;
|
||||
|
||||
WidgetT *root = wgtInitWindow(ctx, win);
|
||||
WidgetT *root = wgtInitWindow(sAc, win);
|
||||
|
||||
// Status label at top
|
||||
WidgetT *status = wgtLabel(root, "Ready.");
|
||||
|
|
@ -1134,48 +1034,17 @@ static void setupWidgetDemo(AppContextT *ctx) {
|
|||
|
||||
|
||||
// ============================================================
|
||||
// main
|
||||
// Entry point
|
||||
// ============================================================
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc;
|
||||
int32_t appMain(DxeAppContextT *ctx) {
|
||||
sDxeCtx = ctx;
|
||||
sAc = ctx->shellCtx;
|
||||
|
||||
// Change to executable's directory so relative BMP paths work
|
||||
char exeDir[260];
|
||||
strncpy(exeDir, argv[0], sizeof(exeDir) - 1);
|
||||
exeDir[sizeof(exeDir) - 1] = '\0';
|
||||
char *lastSep = strrchr(exeDir, '/');
|
||||
char *lastBs = strrchr(exeDir, '\\');
|
||||
if (lastBs > lastSep) {
|
||||
lastSep = lastBs;
|
||||
}
|
||||
if (lastSep) {
|
||||
*lastSep = '\0';
|
||||
chdir(exeDir);
|
||||
}
|
||||
|
||||
AppContextT ctx;
|
||||
|
||||
printf("DVX GUI Demo\n");
|
||||
printf("Initializing VESA video...\n");
|
||||
|
||||
if (dvxInit(&ctx, 1024, 768, 16) != 0) {
|
||||
fprintf(stderr, "Failed to initialize DVX GUI\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sCtx = &ctx;
|
||||
|
||||
setupMainWindow(&ctx);
|
||||
setupWidgetDemo(&ctx);
|
||||
setupControlsWindow(&ctx);
|
||||
setupTerminalWindow(&ctx);
|
||||
|
||||
dvxRun(&ctx);
|
||||
|
||||
dvxShutdown(&ctx);
|
||||
|
||||
printf("DVX GUI Demo ended.\n");
|
||||
setupMainWindow();
|
||||
setupWidgetDemo();
|
||||
setupControlsWindow();
|
||||
setupTerminalWindow();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -35,6 +35,7 @@
|
|||
#define CMD_TILE 201
|
||||
#define CMD_TILE_H 202
|
||||
#define CMD_TILE_V 203
|
||||
#define CMD_MIN_ON_RUN 104
|
||||
#define CMD_ABOUT 300
|
||||
#define CMD_TASK_MGR 301
|
||||
|
||||
|
|
@ -52,6 +53,7 @@ static AppContextT *sAc = NULL;
|
|||
static int32_t sMyAppId = 0;
|
||||
static WindowT *sPmWindow = NULL;
|
||||
static WidgetT *sStatusLabel = NULL;
|
||||
static bool sMinOnRun = false;
|
||||
static AppEntryT sAppFiles[MAX_APP_FILES];
|
||||
static int32_t sAppCount = 0;
|
||||
|
||||
|
|
@ -117,6 +119,9 @@ static void buildPmWindow(void) {
|
|||
wmAddMenuSeparator(fileMenu);
|
||||
wmAddMenuItem(fileMenu, "E&xit Shell", CMD_EXIT);
|
||||
|
||||
MenuT *optMenu = wmAddMenu(menuBar, "&Options");
|
||||
wmAddMenuCheckItem(optMenu, "&Minimize on Run", CMD_MIN_ON_RUN, false);
|
||||
|
||||
MenuT *windowMenu = wmAddMenu(menuBar, "&Window");
|
||||
wmAddMenuItem(windowMenu, "&Cascade", CMD_CASCADE);
|
||||
wmAddMenuItem(windowMenu, "&Tile", CMD_TILE);
|
||||
|
|
@ -242,6 +247,10 @@ static void onAppButtonClick(WidgetT *w) {
|
|||
|
||||
shellLoadApp(sAc, entry->path);
|
||||
updateStatusText();
|
||||
|
||||
if (sMinOnRun && sPmWindow) {
|
||||
dvxMinimizeWindow(sAc, sPmWindow);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -271,6 +280,10 @@ static void onPmMenu(WindowT *win, int32_t menuId) {
|
|||
if (dvxFileDialog(sAc, "Run Application", FD_OPEN, "apps", filters, 2, path, sizeof(path))) {
|
||||
shellLoadApp(sAc, path);
|
||||
updateStatusText();
|
||||
|
||||
if (sMinOnRun && sPmWindow) {
|
||||
dvxMinimizeWindow(sAc, sPmWindow);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -295,6 +308,10 @@ static void onPmMenu(WindowT *win, int32_t menuId) {
|
|||
dvxTileWindowsV(sAc);
|
||||
break;
|
||||
|
||||
case CMD_MIN_ON_RUN:
|
||||
sMinOnRun = !sMinOnRun;
|
||||
break;
|
||||
|
||||
case CMD_ABOUT:
|
||||
showAboutDialog();
|
||||
break;
|
||||
|
|
@ -485,7 +502,7 @@ static void scanAppsDir(void) {
|
|||
|
||||
static void showAboutDialog(void) {
|
||||
dvxMessageBox(sAc, "About DVX Shell",
|
||||
"DVX Shell 1.0\n\nA DOS Visual eXecutive desktop shell for DJGPP/DPMI. Using DXE3 dynamic loading for application modules.",
|
||||
"DVX Shell 1.0\nA DOS Visual eXecutive desktop shell for DJGPP/DPMI. Using DXE3 dynamic loading for application modules.",
|
||||
MB_OK | MB_ICONINFO);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -130,4 +130,4 @@ $(WOBJDIR)/widgetScrollbar.o: widgets/widgetScrollbar.c $(WIDGET_DEPS)
|
|||
$(WOBJDIR)/widgetTreeView.o: widgets/widgetTreeView.c $(WIDGET_DEPS)
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR) $(LIBDIR)
|
||||
rm -f $(OBJS) $(POBJS) $(WOBJS) $(TARGET)
|
||||
|
|
|
|||
58
dvx/dvxApp.c
58
dvx/dvxApp.c
|
|
@ -19,8 +19,12 @@
|
|||
#define KB_MOVE_STEP 8
|
||||
#define MENU_CHECK_WIDTH 14
|
||||
#define SUBMENU_ARROW_WIDTH 12
|
||||
#define SUBMENU_ARROW_HALF 3 // half-size of submenu arrow glyph
|
||||
#define TOOLTIP_DELAY_MS 500
|
||||
#define TOOLTIP_PAD 3
|
||||
#define POPUP_BEVEL_WIDTH 2 // popup menu border bevel thickness
|
||||
#define POPUP_ITEM_PAD_H 8 // extra horizontal padding in popup items
|
||||
#define MENU_TAB_GAP_CHARS 3 // char-widths gap between label and shortcut
|
||||
|
||||
// ============================================================
|
||||
// Prototypes
|
||||
|
|
@ -133,7 +137,7 @@ static void calcPopupSize(const AppContextT *ctx, const MenuT *menu, int32_t *pw
|
|||
memcpy(leftBuf, label, leftLen);
|
||||
leftBuf[leftLen] = '\0';
|
||||
|
||||
itemW = textWidthAccel(&ctx->font, leftBuf) + ctx->font.charWidth * 3 + textWidth(&ctx->font, tab + 1);
|
||||
itemW = textWidthAccel(&ctx->font, leftBuf) + ctx->font.charWidth * MENU_TAB_GAP_CHARS + textWidth(&ctx->font, tab + 1);
|
||||
} else {
|
||||
itemW = textWidthAccel(&ctx->font, label);
|
||||
}
|
||||
|
|
@ -151,8 +155,8 @@ static void calcPopupSize(const AppContextT *ctx, const MenuT *menu, int32_t *pw
|
|||
}
|
||||
}
|
||||
|
||||
*pw = maxW + CHROME_TITLE_PAD * 2 + 8 + (hasSub ? SUBMENU_ARROW_WIDTH : 0) + (hasCheck ? MENU_CHECK_WIDTH : 0);
|
||||
*ph = menu->itemCount * ctx->font.charHeight + 4;
|
||||
*pw = maxW + CHROME_TITLE_PAD * 2 + POPUP_ITEM_PAD_H + (hasSub ? SUBMENU_ARROW_WIDTH : 0) + (hasCheck ? MENU_CHECK_WIDTH : 0);
|
||||
*ph = menu->itemCount * ctx->font.charHeight + POPUP_BEVEL_WIDTH * 2;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -380,16 +384,16 @@ static void compositeAndFlush(AppContextT *ctx) {
|
|||
smBevel.highlight = ctx->colors.windowHighlight;
|
||||
smBevel.shadow = ctx->colors.windowShadow;
|
||||
smBevel.face = ctx->colors.menuBg;
|
||||
smBevel.width = 2;
|
||||
smBevel.width = POPUP_BEVEL_WIDTH;
|
||||
drawBevel(d, ops, ctx->sysMenu.popupX, ctx->sysMenu.popupY, ctx->sysMenu.popupW, ctx->sysMenu.popupH, &smBevel);
|
||||
|
||||
int32_t itemY = ctx->sysMenu.popupY + 2;
|
||||
int32_t itemY = ctx->sysMenu.popupY + POPUP_BEVEL_WIDTH;
|
||||
|
||||
for (int32_t k = 0; k < ctx->sysMenu.itemCount; k++) {
|
||||
SysMenuItemT *item = &ctx->sysMenu.items[k];
|
||||
|
||||
if (item->separator) {
|
||||
drawHLine(d, ops, ctx->sysMenu.popupX + 2, itemY + ctx->font.charHeight / 2, ctx->sysMenu.popupW - 4, ctx->colors.windowShadow);
|
||||
drawHLine(d, ops, ctx->sysMenu.popupX + POPUP_BEVEL_WIDTH, itemY + ctx->font.charHeight / 2, ctx->sysMenu.popupW - POPUP_BEVEL_WIDTH * 2, ctx->colors.windowShadow);
|
||||
itemY += ctx->font.charHeight;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -402,8 +406,8 @@ static void compositeAndFlush(AppContextT *ctx) {
|
|||
fg = ctx->colors.menuHighlightFg;
|
||||
}
|
||||
|
||||
rectFill(d, ops, ctx->sysMenu.popupX + 2, itemY, ctx->sysMenu.popupW - 4, ctx->font.charHeight, bg);
|
||||
drawTextAccel(d, ops, &ctx->font, ctx->sysMenu.popupX + CHROME_TITLE_PAD + 2, itemY, item->label, fg, bg, true);
|
||||
rectFill(d, ops, ctx->sysMenu.popupX + POPUP_BEVEL_WIDTH, itemY, ctx->sysMenu.popupW - POPUP_BEVEL_WIDTH * 2, ctx->font.charHeight, bg);
|
||||
drawTextAccel(d, ops, &ctx->font, ctx->sysMenu.popupX + CHROME_TITLE_PAD + POPUP_BEVEL_WIDTH, itemY, item->label, fg, bg, true);
|
||||
|
||||
itemY += ctx->font.charHeight;
|
||||
}
|
||||
|
|
@ -661,7 +665,7 @@ static void dispatchEvents(AppContextT *ctx) {
|
|||
my >= ctx->sysMenu.popupY && my < ctx->sysMenu.popupY + ctx->sysMenu.popupH) {
|
||||
|
||||
// Hover tracking
|
||||
int32_t relY = my - ctx->sysMenu.popupY - 2;
|
||||
int32_t relY = my - ctx->sysMenu.popupY - POPUP_BEVEL_WIDTH;
|
||||
int32_t itemIdx = (relY >= 0) ? (int32_t)((uint32_t)relY * ctx->charHeightRecip >> 16) : 0;
|
||||
|
||||
if (itemIdx >= 0 && itemIdx < ctx->sysMenu.itemCount && ctx->sysMenu.items[itemIdx].separator) {
|
||||
|
|
@ -701,7 +705,7 @@ static void dispatchEvents(AppContextT *ctx) {
|
|||
|
||||
if (inCurrent) {
|
||||
// Hover tracking in current level
|
||||
int32_t relY = my - ctx->popup.popupY - 2;
|
||||
int32_t relY = my - ctx->popup.popupY - POPUP_BEVEL_WIDTH;
|
||||
int32_t itemIdx = (relY >= 0) ? (int32_t)((uint32_t)relY * ctx->charHeightRecip >> 16) : 0;
|
||||
|
||||
if (itemIdx < 0) {
|
||||
|
|
@ -781,7 +785,7 @@ static void dispatchEvents(AppContextT *ctx) {
|
|||
closePopupLevel(ctx);
|
||||
|
||||
// Now current level IS this parent — update hover
|
||||
int32_t relY = my - ctx->popup.popupY - 2;
|
||||
int32_t relY = my - ctx->popup.popupY - POPUP_BEVEL_WIDTH;
|
||||
int32_t itemIdx = (relY >= 0) ? (int32_t)((uint32_t)relY * ctx->charHeightRecip >> 16) : 0;
|
||||
|
||||
if (itemIdx < 0) {
|
||||
|
|
@ -970,17 +974,17 @@ static void drawPopupLevel(AppContextT *ctx, DisplayT *d, const BlitOpsT *ops, c
|
|||
popBevel.highlight = ctx->colors.windowHighlight;
|
||||
popBevel.shadow = ctx->colors.windowShadow;
|
||||
popBevel.face = ctx->colors.menuBg;
|
||||
popBevel.width = 2;
|
||||
popBevel.width = POPUP_BEVEL_WIDTH;
|
||||
drawBevel(d, ops, px, py, pw, ph, &popBevel);
|
||||
|
||||
// Draw menu items
|
||||
int32_t itemY = py + 2;
|
||||
int32_t itemY = py + POPUP_BEVEL_WIDTH;
|
||||
|
||||
for (int32_t k = 0; k < menu->itemCount; k++) {
|
||||
const MenuItemT *item = &menu->items[k];
|
||||
|
||||
if (item->separator) {
|
||||
drawHLine(d, ops, px + 2, itemY + ctx->font.charHeight / 2, pw - 4, ctx->colors.windowShadow);
|
||||
drawHLine(d, ops, px + POPUP_BEVEL_WIDTH, itemY + ctx->font.charHeight / 2, pw - POPUP_BEVEL_WIDTH * 2, ctx->colors.windowShadow);
|
||||
itemY += ctx->font.charHeight;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -993,7 +997,7 @@ static void drawPopupLevel(AppContextT *ctx, DisplayT *d, const BlitOpsT *ops, c
|
|||
fg = ctx->colors.menuHighlightFg;
|
||||
}
|
||||
|
||||
rectFill(d, ops, px + 2, itemY, pw - 4, ctx->font.charHeight, bg);
|
||||
rectFill(d, ops, px + POPUP_BEVEL_WIDTH, itemY, pw - POPUP_BEVEL_WIDTH * 2, ctx->font.charHeight, bg);
|
||||
|
||||
// Split label at tab: left part is the menu text, right part is the shortcut
|
||||
const char *tab = strchr(item->label, '\t');
|
||||
|
|
@ -1009,11 +1013,11 @@ static void drawPopupLevel(AppContextT *ctx, DisplayT *d, const BlitOpsT *ops, c
|
|||
memcpy(leftBuf, item->label, leftLen);
|
||||
leftBuf[leftLen] = '\0';
|
||||
|
||||
drawTextAccel(d, ops, &ctx->font, px + CHROME_TITLE_PAD + 2 + checkMargin, itemY, leftBuf, fg, bg, true);
|
||||
drawTextAccel(d, ops, &ctx->font, px + CHROME_TITLE_PAD + POPUP_BEVEL_WIDTH + checkMargin, itemY, leftBuf, fg, bg, true);
|
||||
|
||||
const char *right = tab + 1;
|
||||
int32_t rightW = textWidth(&ctx->font, right);
|
||||
int32_t rightX = px + pw - rightW - CHROME_TITLE_PAD - 4;
|
||||
int32_t rightX = px + pw - rightW - CHROME_TITLE_PAD - POPUP_BEVEL_WIDTH * 2;
|
||||
|
||||
if (item->subMenu) {
|
||||
rightX -= SUBMENU_ARROW_WIDTH;
|
||||
|
|
@ -1021,13 +1025,13 @@ static void drawPopupLevel(AppContextT *ctx, DisplayT *d, const BlitOpsT *ops, c
|
|||
|
||||
drawText(d, ops, &ctx->font, rightX, itemY, right, fg, bg, true);
|
||||
} else {
|
||||
drawTextAccel(d, ops, &ctx->font, px + CHROME_TITLE_PAD + 2 + checkMargin, itemY, item->label, fg, bg, true);
|
||||
drawTextAccel(d, ops, &ctx->font, px + CHROME_TITLE_PAD + POPUP_BEVEL_WIDTH + checkMargin, itemY, item->label, fg, bg, true);
|
||||
}
|
||||
|
||||
// Draw check/radio indicator
|
||||
if (item->checked) {
|
||||
int32_t cy = itemY + ctx->font.charHeight / 2;
|
||||
int32_t cx = px + 2 + MENU_CHECK_WIDTH / 2;
|
||||
int32_t cx = px + POPUP_BEVEL_WIDTH + MENU_CHECK_WIDTH / 2;
|
||||
|
||||
if (item->type == MenuItemCheckE) {
|
||||
// Checkmark: small tick shape
|
||||
|
|
@ -1049,14 +1053,14 @@ static void drawPopupLevel(AppContextT *ctx, DisplayT *d, const BlitOpsT *ops, c
|
|||
|
||||
// Draw submenu arrow indicator
|
||||
if (item->subMenu) {
|
||||
int32_t arrowX = px + pw - SUBMENU_ARROW_WIDTH - 2;
|
||||
int32_t arrowX = px + pw - SUBMENU_ARROW_WIDTH - POPUP_BEVEL_WIDTH;
|
||||
int32_t arrowY = itemY + ctx->font.charHeight / 2;
|
||||
|
||||
for (int32_t row = -3; row <= 3; row++) {
|
||||
int32_t len = 4 - (row < 0 ? -row : row);
|
||||
for (int32_t row = -SUBMENU_ARROW_HALF; row <= SUBMENU_ARROW_HALF; row++) {
|
||||
int32_t len = SUBMENU_ARROW_HALF + 1 - (row < 0 ? -row : row);
|
||||
|
||||
if (len > 0) {
|
||||
drawHLine(d, ops, arrowX + (row < 0 ? 3 + row : 3 - row), arrowY + row, len, fg);
|
||||
drawHLine(d, ops, arrowX + (row < 0 ? SUBMENU_ARROW_HALF + row : SUBMENU_ARROW_HALF - row), arrowY + row, len, fg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2078,8 +2082,8 @@ static void openSubMenu(AppContextT *ctx) {
|
|||
|
||||
// Open submenu at right edge of current popup, aligned with hovered item
|
||||
ctx->popup.menu = item->subMenu;
|
||||
ctx->popup.popupX = pl->popupX + pl->popupW - 2;
|
||||
ctx->popup.popupY = pl->popupY + 2 + idx * ctx->font.charHeight;
|
||||
ctx->popup.popupX = pl->popupX + pl->popupW - POPUP_BEVEL_WIDTH;
|
||||
ctx->popup.popupY = pl->popupY + POPUP_BEVEL_WIDTH + idx * ctx->font.charHeight;
|
||||
ctx->popup.hoverItem = -1;
|
||||
|
||||
calcPopupSize(ctx, ctx->popup.menu, &ctx->popup.popupW, &ctx->popup.popupH);
|
||||
|
|
@ -2178,8 +2182,8 @@ static void openSysMenu(AppContextT *ctx, WindowT *win) {
|
|||
}
|
||||
}
|
||||
|
||||
ctx->sysMenu.popupW = maxW + CHROME_TITLE_PAD * 2 + 8;
|
||||
ctx->sysMenu.popupH = ctx->sysMenu.itemCount * ctx->font.charHeight + 4;
|
||||
ctx->sysMenu.popupW = maxW + CHROME_TITLE_PAD * 2 + POPUP_ITEM_PAD_H;
|
||||
ctx->sysMenu.popupH = ctx->sysMenu.itemCount * ctx->font.charHeight + POPUP_BEVEL_WIDTH * 2;
|
||||
ctx->sysMenu.hoverItem = -1;
|
||||
ctx->sysMenu.active = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,12 @@
|
|||
#define BUTTON_WIDTH 80
|
||||
#define BUTTON_HEIGHT 24
|
||||
#define BUTTON_GAP 8
|
||||
#define ICON_GLYPH_SIZE 24 // icon glyph drawing area (pixels)
|
||||
#define ICON_GLYPH_CENTER 12 // center of icon glyph (ICON_GLYPH_SIZE / 2)
|
||||
#define ICON_OUTER_R2 144 // outer circle radius squared (12*12)
|
||||
#define ICON_INNER_R2 100 // inner circle radius squared (10*10)
|
||||
#define FD_DIALOG_WIDTH 360 // file dialog window width
|
||||
#define FD_DIALOG_HEIGHT 340 // file dialog window height
|
||||
|
||||
// ============================================================
|
||||
// Prototypes
|
||||
|
|
@ -75,13 +81,13 @@ static MsgBoxStateT sMsgBox;
|
|||
static void drawIconGlyph(DisplayT *d, const BlitOpsT *ops, int32_t x, int32_t y, int32_t iconType, uint32_t color) {
|
||||
if (iconType == MB_ICONINFO) {
|
||||
// Circle outline with 'i'
|
||||
for (int32_t row = 0; row < 24; row++) {
|
||||
for (int32_t col = 0; col < 24; col++) {
|
||||
int32_t dx = col - 12;
|
||||
int32_t dy = row - 12;
|
||||
for (int32_t row = 0; row < ICON_GLYPH_SIZE; row++) {
|
||||
for (int32_t col = 0; col < ICON_GLYPH_SIZE; col++) {
|
||||
int32_t dx = col - ICON_GLYPH_CENTER;
|
||||
int32_t dy = row - ICON_GLYPH_CENTER;
|
||||
int32_t d2 = dx * dx + dy * dy;
|
||||
|
||||
if (d2 <= 144 && d2 >= 100) {
|
||||
if (d2 <= ICON_OUTER_R2 && d2 >= ICON_INNER_R2) {
|
||||
rectFill(d, ops, x + col, y + row, 1, 1, color);
|
||||
}
|
||||
}
|
||||
|
|
@ -91,15 +97,15 @@ static void drawIconGlyph(DisplayT *d, const BlitOpsT *ops, int32_t x, int32_t y
|
|||
rectFill(d, ops, x + 11, y + 10, 2, 8, color);
|
||||
} else if (iconType == MB_ICONWARNING) {
|
||||
// Triangle outline with '!'
|
||||
for (int32_t row = 0; row < 24; row++) {
|
||||
for (int32_t row = 0; row < ICON_GLYPH_SIZE; row++) {
|
||||
int32_t halfW = row / 2;
|
||||
int32_t lx = 12 - halfW;
|
||||
int32_t rx = 12 + halfW;
|
||||
int32_t lx = ICON_GLYPH_CENTER - halfW;
|
||||
int32_t rx = ICON_GLYPH_CENTER + halfW;
|
||||
|
||||
rectFill(d, ops, x + lx, y + row, 1, 1, color);
|
||||
rectFill(d, ops, x + rx, y + row, 1, 1, color);
|
||||
|
||||
if (row == 23) {
|
||||
if (row == ICON_GLYPH_SIZE - 1) {
|
||||
drawHLine(d, ops, x + lx, y + row, rx - lx + 1, color);
|
||||
}
|
||||
}
|
||||
|
|
@ -108,31 +114,31 @@ static void drawIconGlyph(DisplayT *d, const BlitOpsT *ops, int32_t x, int32_t y
|
|||
rectFill(d, ops, x + 11, y + 19, 2, 2, color);
|
||||
} else if (iconType == MB_ICONERROR) {
|
||||
// Circle outline with X
|
||||
for (int32_t row = 0; row < 24; row++) {
|
||||
for (int32_t col = 0; col < 24; col++) {
|
||||
int32_t dx = col - 12;
|
||||
int32_t dy = row - 12;
|
||||
for (int32_t row = 0; row < ICON_GLYPH_SIZE; row++) {
|
||||
for (int32_t col = 0; col < ICON_GLYPH_SIZE; col++) {
|
||||
int32_t dx = col - ICON_GLYPH_CENTER;
|
||||
int32_t dy = row - ICON_GLYPH_CENTER;
|
||||
int32_t d2 = dx * dx + dy * dy;
|
||||
|
||||
if (d2 <= 144 && d2 >= 100) {
|
||||
if (d2 <= ICON_OUTER_R2 && d2 >= ICON_INNER_R2) {
|
||||
rectFill(d, ops, x + col, y + row, 1, 1, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < 12; i++) {
|
||||
for (int32_t i = 0; i < ICON_GLYPH_CENTER; i++) {
|
||||
rectFill(d, ops, x + 6 + i, y + 6 + i, 2, 2, color);
|
||||
rectFill(d, ops, x + 18 - i, y + 6 + i, 2, 2, color);
|
||||
}
|
||||
} else if (iconType == MB_ICONQUESTION) {
|
||||
// Circle outline with '?'
|
||||
for (int32_t row = 0; row < 24; row++) {
|
||||
for (int32_t col = 0; col < 24; col++) {
|
||||
int32_t dx = col - 12;
|
||||
int32_t dy = row - 12;
|
||||
for (int32_t row = 0; row < ICON_GLYPH_SIZE; row++) {
|
||||
for (int32_t col = 0; col < ICON_GLYPH_SIZE; col++) {
|
||||
int32_t dx = col - ICON_GLYPH_CENTER;
|
||||
int32_t dy = row - ICON_GLYPH_CENTER;
|
||||
int32_t d2 = dx * dx + dy * dy;
|
||||
|
||||
if (d2 <= 144 && d2 >= 100) {
|
||||
if (d2 <= ICON_OUTER_R2 && d2 >= ICON_INNER_R2) {
|
||||
rectFill(d, ops, x + col, y + row, 1, 1, color);
|
||||
}
|
||||
}
|
||||
|
|
@ -214,7 +220,7 @@ int32_t dvxMessageBox(AppContextT *ctx, const char *title, const char *message,
|
|||
|
||||
// Calculate content area sizes
|
||||
int32_t msgAreaH = textH + MSG_PADDING * 2;
|
||||
int32_t iconAreaH = hasIcon ? (24 + MSG_PADDING * 2) : 0;
|
||||
int32_t iconAreaH = hasIcon ? (ICON_GLYPH_SIZE + MSG_PADDING * 2) : 0;
|
||||
|
||||
if (msgAreaH < iconAreaH) {
|
||||
msgAreaH = iconAreaH;
|
||||
|
|
@ -982,8 +988,8 @@ bool dvxFileDialog(AppContextT *ctx, const char *title, int32_t flags, const cha
|
|||
sFd.curDir[FD_MAX_PATH - 1] = '\0';
|
||||
|
||||
// Create dialog window
|
||||
int32_t dlgW = 360;
|
||||
int32_t dlgH = 340;
|
||||
int32_t dlgW = FD_DIALOG_WIDTH;
|
||||
int32_t dlgH = FD_DIALOG_HEIGHT;
|
||||
int32_t winX = (ctx->display.width - dlgW) / 2;
|
||||
int32_t winY = (ctx->display.height - dlgH) / 2;
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,8 @@ typedef struct {
|
|||
// Bitmap font
|
||||
// ============================================================
|
||||
|
||||
#define FONT_CHAR_WIDTH 8 // fixed glyph width in pixels
|
||||
|
||||
typedef struct {
|
||||
int32_t charWidth; // fixed width per glyph (e.g. 8)
|
||||
int32_t charHeight; // e.g. 14 or 16
|
||||
|
|
|
|||
|
|
@ -448,6 +448,7 @@ typedef struct WidgetT {
|
|||
int32_t penSize;
|
||||
int32_t lastX;
|
||||
int32_t lastY;
|
||||
void (*onMouse)(struct WidgetT *w, int32_t cx, int32_t cy, bool drag);
|
||||
} canvas;
|
||||
|
||||
AnsiTermDataT *ansiTerm;
|
||||
|
|
@ -680,6 +681,10 @@ void wgtCanvasSetPenColor(WidgetT *w, uint32_t color);
|
|||
// Set the pen size in pixels (diameter).
|
||||
void wgtCanvasSetPenSize(WidgetT *w, int32_t size);
|
||||
|
||||
// Set the mouse callback. Called on click (drag=false) and drag (drag=true)
|
||||
// with canvas-relative coordinates. If NULL (default), mouse events are ignored.
|
||||
void wgtCanvasSetMouseCallback(WidgetT *w, void (*cb)(WidgetT *w, int32_t cx, int32_t cy, bool drag));
|
||||
|
||||
// Save the canvas to a PNG file. Returns 0 on success, -1 on failure.
|
||||
int32_t wgtCanvasSave(WidgetT *w, const char *path);
|
||||
|
||||
|
|
|
|||
85
dvx/dvxWm.c
85
dvx/dvxWm.c
|
|
@ -17,6 +17,14 @@
|
|||
|
||||
#define GADGET_PAD 2
|
||||
#define GADGET_INSET 2 // inset from title bar edges
|
||||
#define MENU_BAR_GAP 8 // horizontal gap between menu bar labels
|
||||
#define RESIZE_BREAK_INSET 16 // distance from corner to resize groove
|
||||
#define CLOSE_ICON_INSET 3 // close bar inset from gadget edges
|
||||
#define MAXIMIZE_ICON_INSET 2 // maximize box inset from gadget edges
|
||||
#define RESTORE_ICON_INSET 4 // restore box inset from gadget edges
|
||||
#define MINIMIZE_ICON_SIZE 4 // filled square size for minimize icon
|
||||
#define SB_ARROW_ROWS 4 // number of rows in scrollbar arrow glyph
|
||||
#define SB_ARROW_HALF 2 // half-width of scrollbar arrow tip
|
||||
|
||||
// ============================================================
|
||||
// Title bar gadget geometry
|
||||
|
|
@ -78,7 +86,7 @@ static void computeMenuBarPositions(WindowT *win, const BitmapFontT *font) {
|
|||
|
||||
menu->barX = x;
|
||||
menu->barW = labelW;
|
||||
x += labelW;
|
||||
x += labelW + MENU_BAR_GAP;
|
||||
}
|
||||
|
||||
win->menuBar->positionsDirty = false;
|
||||
|
|
@ -201,6 +209,14 @@ static void drawMenuBar(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *fon
|
|||
rectFill(d, ops, win->x + CHROME_BORDER_WIDTH, barY,
|
||||
win->w - CHROME_BORDER_WIDTH * 2, barH, colors->menuBg);
|
||||
|
||||
// Clip menu labels to the menu bar area
|
||||
int32_t savedClipX = d->clipX;
|
||||
int32_t savedClipY = d->clipY;
|
||||
int32_t savedClipW = d->clipW;
|
||||
int32_t savedClipH = d->clipH;
|
||||
setClipRect(d, win->x + CHROME_BORDER_WIDTH, barY,
|
||||
win->w - CHROME_BORDER_WIDTH * 2, barH);
|
||||
|
||||
// Draw each menu label
|
||||
for (int32_t i = 0; i < win->menuBar->menuCount; i++) {
|
||||
MenuT *menu = &win->menuBar->menus[i];
|
||||
|
|
@ -211,6 +227,8 @@ static void drawMenuBar(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *fon
|
|||
colors->menuFg, colors->menuBg, true);
|
||||
}
|
||||
|
||||
setClipRect(d, savedClipX, savedClipY, savedClipW, savedClipH);
|
||||
|
||||
// Draw bottom separator line
|
||||
drawHLine(d, ops, win->x + CHROME_BORDER_WIDTH, barY + barH - 1,
|
||||
win->w - CHROME_BORDER_WIDTH * 2, colors->windowShadow);
|
||||
|
|
@ -234,7 +252,7 @@ static void drawResizeBreaks(DisplayT *d, const BlitOpsT *ops, const ColorScheme
|
|||
uint32_t hi = colors->windowHighlight;
|
||||
uint32_t sh = colors->windowShadow;
|
||||
int32_t bw = CHROME_BORDER_WIDTH;
|
||||
int32_t inset = 16; // distance from corner to groove
|
||||
int32_t inset = RESIZE_BREAK_INSET;
|
||||
int32_t wx = win->x;
|
||||
int32_t wy = win->y;
|
||||
int32_t ww = win->w;
|
||||
|
|
@ -416,23 +434,23 @@ static void drawScrollbarArrow(DisplayT *d, const BlitOpsT *ops, const ColorSche
|
|||
int32_t cy = y + size / 2;
|
||||
uint32_t fg = colors->contentFg;
|
||||
|
||||
// Draw a small 5-row triangle
|
||||
for (int32_t i = 0; i < 4; i++) {
|
||||
// Draw a small triangle
|
||||
for (int32_t i = 0; i < SB_ARROW_ROWS; i++) {
|
||||
switch (dir) {
|
||||
case 0: // up
|
||||
drawHLine(d, ops, cx - i, cy - 2 + i, 1 + i * 2, fg);
|
||||
drawHLine(d, ops, cx - i, cy - SB_ARROW_HALF + i, 1 + i * 2, fg);
|
||||
break;
|
||||
|
||||
case 1: // down
|
||||
drawHLine(d, ops, cx - i, cy + 2 - i, 1 + i * 2, fg);
|
||||
drawHLine(d, ops, cx - i, cy + SB_ARROW_HALF - i, 1 + i * 2, fg);
|
||||
break;
|
||||
|
||||
case 2: // left
|
||||
drawVLine(d, ops, cx - 2 + i, cy - i, 1 + i * 2, fg);
|
||||
drawVLine(d, ops, cx - SB_ARROW_HALF + i, cy - i, 1 + i * 2, fg);
|
||||
break;
|
||||
|
||||
case 3: // right
|
||||
drawVLine(d, ops, cx + 2 - i, cy - i, 1 + i * 2, fg);
|
||||
drawVLine(d, ops, cx + SB_ARROW_HALF - i, cy - i, 1 + i * 2, fg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -456,32 +474,34 @@ static void drawTitleBar(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *fo
|
|||
// Close gadget on the LEFT (system menu / close)
|
||||
drawTitleGadget(d, ops, colors, g.closeX, g.gadgetY, g.gadgetS);
|
||||
// Horizontal bar icon inside close gadget
|
||||
drawHLine(d, ops, g.closeX + 3, g.gadgetY + g.gadgetS / 2,
|
||||
g.gadgetS - 6, colors->contentFg);
|
||||
drawHLine(d, ops, g.closeX + CLOSE_ICON_INSET, g.gadgetY + g.gadgetS / 2,
|
||||
g.gadgetS - CLOSE_ICON_INSET * 2, colors->contentFg);
|
||||
|
||||
if (g.maxX >= 0) {
|
||||
// Maximize/restore gadget on the far RIGHT
|
||||
drawTitleGadget(d, ops, colors, g.maxX, g.gadgetY, g.gadgetS);
|
||||
|
||||
if (win->maximized) {
|
||||
// Restore icon: larger box outline filling more of the gadget
|
||||
int32_t bx = g.maxX + 2;
|
||||
int32_t by = g.gadgetY + 2;
|
||||
int32_t bs = g.gadgetS - 4;
|
||||
// Restore icon: small box outline
|
||||
int32_t bx = g.maxX + RESTORE_ICON_INSET;
|
||||
int32_t by = g.gadgetY + RESTORE_ICON_INSET;
|
||||
int32_t bs = g.gadgetS - RESTORE_ICON_INSET * 2;
|
||||
rectFill(d, ops, bx, by, bs, bs, colors->buttonFace);
|
||||
drawHLine(d, ops, bx, by, bs, colors->contentFg);
|
||||
drawHLine(d, ops, bx, by + bs - 1, bs, colors->contentFg);
|
||||
drawVLine(d, ops, bx, by, bs, colors->contentFg);
|
||||
drawVLine(d, ops, bx + bs - 1, by, bs, colors->contentFg);
|
||||
} else {
|
||||
// Maximize icon: larger box outline filling more of the gadget
|
||||
int32_t bx = g.maxX + MAXIMIZE_ICON_INSET;
|
||||
int32_t by = g.gadgetY + MAXIMIZE_ICON_INSET;
|
||||
int32_t bs = g.gadgetS - MAXIMIZE_ICON_INSET * 2;
|
||||
rectFill(d, ops, bx, by, bs, bs, colors->buttonFace);
|
||||
drawHLine(d, ops, bx, by, bs, colors->contentFg);
|
||||
drawHLine(d, ops, bx, by + 1, bs, colors->contentFg);
|
||||
drawHLine(d, ops, bx, by + bs - 1, bs, colors->contentFg);
|
||||
drawVLine(d, ops, bx, by, bs, colors->contentFg);
|
||||
drawVLine(d, ops, bx + bs - 1, by, bs, colors->contentFg);
|
||||
} else {
|
||||
// Maximize icon: small box outline
|
||||
rectFill(d, ops, g.maxX + 3, g.gadgetY + 3,
|
||||
g.gadgetS - 6, g.gadgetS - 6, colors->buttonFace);
|
||||
drawHLine(d, ops, g.maxX + 3, g.gadgetY + 3, g.gadgetS - 6, colors->contentFg);
|
||||
drawHLine(d, ops, g.maxX + 3, g.gadgetY + g.gadgetS - 4, g.gadgetS - 6, colors->contentFg);
|
||||
drawVLine(d, ops, g.maxX + 3, g.gadgetY + 3, g.gadgetS - 6, colors->contentFg);
|
||||
drawVLine(d, ops, g.maxX + g.gadgetS - 4, g.gadgetY + 3, g.gadgetS - 6, colors->contentFg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -489,9 +509,8 @@ static void drawTitleBar(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *fo
|
|||
if (g.minX >= 0) {
|
||||
drawTitleGadget(d, ops, colors, g.minX, g.gadgetY, g.gadgetS);
|
||||
// Small square centered in minimize gadget
|
||||
int32_t miniSize = 4;
|
||||
rectFill(d, ops, g.minX + (g.gadgetS - miniSize) / 2, g.gadgetY + (g.gadgetS - miniSize) / 2,
|
||||
miniSize, miniSize, colors->contentFg);
|
||||
rectFill(d, ops, g.minX + (g.gadgetS - MINIMIZE_ICON_SIZE) / 2, g.gadgetY + (g.gadgetS - MINIMIZE_ICON_SIZE) / 2,
|
||||
MINIMIZE_ICON_SIZE, MINIMIZE_ICON_SIZE, colors->contentFg);
|
||||
}
|
||||
|
||||
// Title text — centered between close gadget and minimize, truncated to fit
|
||||
|
|
@ -1343,9 +1362,9 @@ int32_t wmMinimizedIconHit(const WindowStackT *stack, const DisplayT *d, int32_t
|
|||
|
||||
static void wmMinWindowSize(const WindowT *win, int32_t *minW, int32_t *minH) {
|
||||
// Title bar: close gadget + padding + 1 char of title + padding
|
||||
int32_t gadgetS = CHROME_TITLE_HEIGHT - 4;
|
||||
int32_t gadgetPad = 2;
|
||||
int32_t charW = 8; // bitmap font char width
|
||||
int32_t gadgetS = CHROME_TITLE_HEIGHT - GADGET_INSET * 2;
|
||||
int32_t gadgetPad = GADGET_PAD;
|
||||
int32_t charW = FONT_CHAR_WIDTH;
|
||||
|
||||
// Minimum title bar width: close gadget + 1 char + minimize gadget + padding
|
||||
int32_t titleMinW = gadgetPad + gadgetS + gadgetPad + charW + gadgetPad + gadgetS + gadgetPad;
|
||||
|
|
@ -1357,6 +1376,16 @@ static void wmMinWindowSize(const WindowT *win, int32_t *minW, int32_t *minH) {
|
|||
|
||||
*minW = titleMinW + CHROME_BORDER_WIDTH * 2;
|
||||
|
||||
// Menu bar width: ensure window is wide enough to show all menu labels
|
||||
if (win->menuBar && win->menuBar->menuCount > 0) {
|
||||
MenuT *last = &win->menuBar->menus[win->menuBar->menuCount - 1];
|
||||
int32_t menuW = last->barX + last->barW + CHROME_TOTAL_SIDE;
|
||||
|
||||
if (menuW > *minW) {
|
||||
*minW = menuW;
|
||||
}
|
||||
}
|
||||
|
||||
// Minimum height: border + title + inner border + some content + bottom chrome
|
||||
*minH = CHROME_TOTAL_TOP + CHROME_TOTAL_BOTTOM + 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -98,8 +98,8 @@ void widgetButtonPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bitma
|
|||
int32_t textY = w->y + (w->h - font->charHeight) / 2;
|
||||
|
||||
if (w->as.button.pressed) {
|
||||
textX++;
|
||||
textY++;
|
||||
textX += BUTTON_PRESS_OFFSET;
|
||||
textY += BUTTON_PRESS_OFFSET;
|
||||
}
|
||||
|
||||
if (!w->enabled) {
|
||||
|
|
@ -109,7 +109,7 @@ void widgetButtonPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bitma
|
|||
}
|
||||
|
||||
if (w->focused) {
|
||||
int32_t off = w->as.button.pressed ? 1 : 0;
|
||||
drawFocusRect(d, ops, w->x + 3 + off, w->y + 3 + off, w->w - 6, w->h - 6, fg);
|
||||
int32_t off = w->as.button.pressed ? BUTTON_PRESS_OFFSET : 0;
|
||||
drawFocusRect(d, ops, w->x + BUTTON_FOCUS_INSET + off, w->y + BUTTON_FOCUS_INSET + off, w->w - BUTTON_FOCUS_INSET * 2, w->h - BUTTON_FOCUS_INSET * 2, fg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -621,6 +621,17 @@ int32_t wgtCanvasSave(WidgetT *w, const char *path) {
|
|||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// wgtCanvasSetMouseCallback
|
||||
// ============================================================
|
||||
|
||||
void wgtCanvasSetMouseCallback(WidgetT *w, void (*cb)(WidgetT *w, int32_t cx, int32_t cy, bool drag)) {
|
||||
if (w && w->type == WidgetCanvasE) {
|
||||
w->as.canvas.onMouse = cb;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// wgtCanvasSetPenColor
|
||||
// ============================================================
|
||||
|
|
@ -689,26 +700,25 @@ void widgetCanvasCalcMinSize(WidgetT *w, const BitmapFontT *font) {
|
|||
|
||||
void widgetCanvasOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) {
|
||||
(void)root;
|
||||
|
||||
if (!hit->as.canvas.onMouse) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert widget coords to canvas coords
|
||||
int32_t cx = vx - hit->x - CANVAS_BORDER;
|
||||
int32_t cy = vy - hit->y - CANVAS_BORDER;
|
||||
|
||||
if (sDrawingCanvas == hit) {
|
||||
// Continuation of a drag stroke — draw line from last to current
|
||||
if (hit->as.canvas.lastX >= 0) {
|
||||
canvasDrawLine(hit, hit->as.canvas.lastX, hit->as.canvas.lastY, cx, cy);
|
||||
} else {
|
||||
canvasDrawDot(hit, cx, cy);
|
||||
}
|
||||
} else {
|
||||
// First click — start drawing, place a dot
|
||||
bool drag = (sDrawingCanvas == hit);
|
||||
|
||||
if (!drag) {
|
||||
sDrawingCanvas = hit;
|
||||
canvasDrawDot(hit, cx, cy);
|
||||
}
|
||||
|
||||
hit->as.canvas.lastX = cx;
|
||||
hit->as.canvas.lastY = cy;
|
||||
|
||||
hit->as.canvas.onMouse(hit, cx, cy, drag);
|
||||
wgtInvalidatePaint(hit);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -262,8 +262,8 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) {
|
|||
int32_t delta = x - sResizeStartX;
|
||||
int32_t newW = sResizeOrigW + delta;
|
||||
|
||||
if (newW < 20) {
|
||||
newW = 20;
|
||||
if (newW < LISTVIEW_MIN_COL_W) {
|
||||
newW = LISTVIEW_MIN_COL_W;
|
||||
}
|
||||
|
||||
if (newW != sResizeListView->as.listView->resolvedColW[sResizeCol]) {
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ extern const WidgetClassT *widgetClassTable[];
|
|||
#define SEPARATOR_THICKNESS 2
|
||||
#define BUTTON_PAD_H 8
|
||||
#define BUTTON_PAD_V 4
|
||||
#define BUTTON_FOCUS_INSET 3 // focus rect inset from button edge
|
||||
#define BUTTON_PRESS_OFFSET 1 // text/focus shift when button is pressed
|
||||
#define CHECKBOX_BOX_SIZE 12
|
||||
#define CHECKBOX_GAP 4
|
||||
#define FRAME_BEVEL_BORDER 2
|
||||
|
|
@ -75,6 +77,7 @@ extern const WidgetClassT *widgetClassTable[];
|
|||
#define TAB_BORDER 2
|
||||
#define LISTBOX_BORDER 2
|
||||
#define LISTVIEW_BORDER 2
|
||||
#define LISTVIEW_MIN_COL_W 20 // minimum column width during resize
|
||||
#define TREE_INDENT 16
|
||||
#define TREE_EXPAND_SIZE 9
|
||||
#define TREE_ICON_GAP 4
|
||||
|
|
@ -84,6 +87,8 @@ extern const WidgetClassT *widgetClassTable[];
|
|||
#define SB_MIN_THUMB 14
|
||||
#define SPLITTER_BAR_W 5
|
||||
#define SPLITTER_MIN_PANE 20
|
||||
#define TOOLBAR_PAD 2 // padding inside toolbar/statusbar
|
||||
#define TOOLBAR_GAP 2 // gap between toolbar/statusbar children
|
||||
|
||||
// ============================================================
|
||||
// Inline helpers
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ void widgetCalcMinSizeBox(WidgetT *w, const BitmapFontT *font) {
|
|||
|
||||
// Toolbar and StatusBar use tighter padding
|
||||
if (w->type == WidgetToolbarE || w->type == WidgetStatusBarE) {
|
||||
pad = 2;
|
||||
gap = 2;
|
||||
pad = TOOLBAR_PAD;
|
||||
gap = TOOLBAR_GAP;
|
||||
}
|
||||
|
||||
for (WidgetT *c = w->firstChild; c; c = c->nextSibling) {
|
||||
|
|
@ -145,8 +145,8 @@ void widgetLayoutBox(WidgetT *w, const BitmapFontT *font) {
|
|||
|
||||
// Toolbar and StatusBar use tighter padding
|
||||
if (w->type == WidgetToolbarE || w->type == WidgetStatusBarE) {
|
||||
pad = 2;
|
||||
gap = 2;
|
||||
pad = TOOLBAR_PAD;
|
||||
gap = TOOLBAR_GAP;
|
||||
}
|
||||
|
||||
int32_t innerX = w->x + pad + fb;
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
# DVX GUI Demo Makefile for DJGPP cross-compilation
|
||||
|
||||
DJGPP_PREFIX = $(HOME)/djgpp/djgpp
|
||||
CC = $(DJGPP_PREFIX)/bin/i586-pc-msdosdjgpp-gcc
|
||||
EXE2COFF = $(DJGPP_PREFIX)/i586-pc-msdosdjgpp/bin/exe2coff
|
||||
CWSDSTUB = $(DJGPP_PREFIX)/i586-pc-msdosdjgpp/bin/CWSDSTUB.EXE
|
||||
CFLAGS = -O2 -Wall -Wextra -march=i486 -mtune=i586 -I../dvx
|
||||
LDFLAGS = -L../lib -ldvx -lm
|
||||
|
||||
OBJDIR = ../obj/dvxdemo
|
||||
BINDIR = ../bin
|
||||
LIBDIR = ../lib
|
||||
|
||||
SRCS = demo.c
|
||||
OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(SRCS))
|
||||
TARGET = $(BINDIR)/demo.exe
|
||||
BMPS = $(wildcard *.bmp)
|
||||
|
||||
.PHONY: all clean lib
|
||||
|
||||
all: lib $(TARGET) $(addprefix $(BINDIR)/,$(BMPS))
|
||||
|
||||
lib:
|
||||
$(MAKE) -C ../dvx
|
||||
|
||||
$(TARGET): $(OBJS) $(LIBDIR)/libdvx.a | $(BINDIR)
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS)
|
||||
$(EXE2COFF) $@
|
||||
cat $(CWSDSTUB) $(BINDIR)/demo > $@
|
||||
rm -f $(BINDIR)/demo
|
||||
|
||||
$(OBJDIR)/%.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir -p $(OBJDIR)
|
||||
|
||||
$(BINDIR):
|
||||
mkdir -p $(BINDIR)
|
||||
|
||||
$(BINDIR)/%.bmp: %.bmp | $(BINDIR)
|
||||
cp $< $@
|
||||
|
||||
# Dependencies
|
||||
$(OBJDIR)/demo.o: demo.c ../dvx/dvxApp.h ../dvx/dvxWidget.h
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR) $(BINDIR)
|
||||
|
|
@ -14,7 +14,7 @@ LIBDIR = ../lib
|
|||
|
||||
SRCS = shellMain.c shellApp.c shellExport.c
|
||||
OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(SRCS))
|
||||
TARGET = $(BINDIR)/dvxshell.exe
|
||||
TARGET = $(BINDIR)/dvx.exe
|
||||
|
||||
.PHONY: all clean libs
|
||||
|
||||
|
|
@ -25,10 +25,10 @@ libs:
|
|||
$(MAKE) -C ../tasks
|
||||
|
||||
$(TARGET): $(OBJS) $(LIBDIR)/libdvx.a $(LIBDIR)/libtasks.a | $(BINDIR)
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS) -Wl,-Map=$(BINDIR)/dvxshell.map
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS) -Wl,-Map=$(BINDIR)/dvx.map
|
||||
$(EXE2COFF) $@
|
||||
cat $(CWSDSTUB) $(BINDIR)/dvxshell > $@
|
||||
rm -f $(BINDIR)/dvxshell
|
||||
cat $(CWSDSTUB) $(BINDIR)/dvx > $@
|
||||
rm -f $(BINDIR)/dvx
|
||||
|
||||
$(OBJDIR)/%.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
|
@ -44,4 +44,4 @@ $(OBJDIR)/shellMain.o: shellMain.c shellApp.h ../dvx/dvxApp.h ../dvx/dvxDialo
|
|||
$(OBJDIR)/shellApp.o: shellApp.c shellApp.h ../dvx/dvxApp.h ../dvx/dvxDialog.h ../tasks/taskswitch.h
|
||||
$(OBJDIR)/shellExport.o: shellExport.c shellApp.h ../dvx/dvxApp.h ../dvx/dvxDialog.h ../dvx/dvxWidget.h ../dvx/dvxDraw.h ../dvx/dvxVideo.h ../dvx/dvxWm.h ../tasks/taskswitch.h
|
||||
clean:
|
||||
rm -rf $(OBJDIR) $(TARGET)
|
||||
rm -f $(OBJS) $(TARGET) $(BINDIR)/dvx.map $(BINDIR)/dvx.log
|
||||
|
|
|
|||
|
|
@ -182,6 +182,23 @@ int32_t shellLoadApp(AppContextT *ctx, const char *path) {
|
|||
app->dxeCtx.shellCtx = ctx;
|
||||
app->dxeCtx.appId = id;
|
||||
|
||||
// Derive app directory from path (everything up to last '/' or '\')
|
||||
snprintf(app->dxeCtx.appDir, sizeof(app->dxeCtx.appDir), "%s", path);
|
||||
|
||||
char *lastSlash = strrchr(app->dxeCtx.appDir, '/');
|
||||
char *lastBack = strrchr(app->dxeCtx.appDir, '\\');
|
||||
|
||||
if (lastBack > lastSlash) {
|
||||
lastSlash = lastBack;
|
||||
}
|
||||
|
||||
if (lastSlash) {
|
||||
*lastSlash = '\0';
|
||||
} else {
|
||||
app->dxeCtx.appDir[0] = '.';
|
||||
app->dxeCtx.appDir[1] = '\0';
|
||||
}
|
||||
|
||||
// Launch
|
||||
sCurrentAppId = id;
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
AppContextT *shellCtx; // the shell's GUI context
|
||||
int32_t appId; // this app's ID
|
||||
char appDir[260]; // directory containing the .app file
|
||||
} DxeAppContextT;
|
||||
|
||||
// ============================================================
|
||||
|
|
@ -95,7 +96,7 @@ int32_t shellRunningAppCount(void);
|
|||
// Logging
|
||||
// ============================================================
|
||||
|
||||
// Write a printf-style message to SHELL.LOG
|
||||
// Write a printf-style message to DVX.LOG
|
||||
void shellLog(const char *fmt, ...);
|
||||
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
// ============================================================
|
||||
// Constants
|
||||
|
|
@ -55,12 +56,13 @@ static void onAppButtonClick(WidgetT *w);
|
|||
static void onPmClose(WindowT *win);
|
||||
static void onPmMenu(WindowT *win, int32_t menuId);
|
||||
static void scanAppsDir(void);
|
||||
static void scanAppsDirRecurse(const char *dirPath);
|
||||
static void showAboutDialog(void);
|
||||
static void updateStatusText(void);
|
||||
|
||||
// Task Manager
|
||||
static WindowT *sTmWindow = NULL;
|
||||
static WidgetT *sTmListBox = NULL;
|
||||
static WidgetT *sTmListView = NULL;
|
||||
static void buildTaskManager(void);
|
||||
static void onTmClose(WindowT *win);
|
||||
static void onTmEndTask(WidgetT *w);
|
||||
|
|
@ -181,10 +183,17 @@ static void buildTaskManager(void) {
|
|||
|
||||
WidgetT *root = wgtInitWindow(sCtx, sTmWindow);
|
||||
|
||||
// List box of running apps
|
||||
sTmListBox = wgtListBox(root);
|
||||
sTmListBox->weight = 100;
|
||||
sTmListBox->prefH = wgtPixels(160);
|
||||
// List view of running apps
|
||||
static const ListViewColT tmCols[] = {
|
||||
{ "Name", wgtPercent(50), ListViewAlignLeftE },
|
||||
{ "Type", wgtPercent(25), ListViewAlignLeftE },
|
||||
{ "Status", wgtPercent(25), ListViewAlignLeftE },
|
||||
};
|
||||
|
||||
sTmListView = wgtListView(root);
|
||||
sTmListView->weight = 100;
|
||||
sTmListView->prefH = wgtPixels(160);
|
||||
wgtListViewSetColumns(sTmListView, tmCols, 3);
|
||||
|
||||
// Button row
|
||||
WidgetT *btnRow = wgtHBox(root);
|
||||
|
|
@ -278,7 +287,7 @@ static void onPmMenu(WindowT *win, int32_t menuId) {
|
|||
|
||||
|
||||
static void onTmClose(WindowT *win) {
|
||||
sTmListBox = NULL;
|
||||
sTmListView = NULL;
|
||||
sTmWindow = NULL;
|
||||
dvxDestroyWindow(sCtx, win);
|
||||
}
|
||||
|
|
@ -287,11 +296,11 @@ static void onTmClose(WindowT *win) {
|
|||
static void onTmEndTask(WidgetT *w) {
|
||||
(void)w;
|
||||
|
||||
if (!sTmListBox) {
|
||||
if (!sTmListView) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t sel = wgtListBoxGetSelected(sTmListBox);
|
||||
int32_t sel = wgtListViewGetSelected(sTmListView);
|
||||
|
||||
if (sel < 0) {
|
||||
return;
|
||||
|
|
@ -320,11 +329,11 @@ static void onTmEndTask(WidgetT *w) {
|
|||
static void onTmSwitchTo(WidgetT *w) {
|
||||
(void)w;
|
||||
|
||||
if (!sTmListBox) {
|
||||
if (!sTmListView) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t sel = wgtListBoxGetSelected(sTmListBox);
|
||||
int32_t sel = wgtListViewGetSelected(sTmListView);
|
||||
|
||||
if (sel < 0) {
|
||||
return;
|
||||
|
|
@ -363,41 +372,69 @@ static void onTmSwitchTo(WidgetT *w) {
|
|||
|
||||
|
||||
static void refreshTaskList(void) {
|
||||
if (!sTmListBox) {
|
||||
if (!sTmListView) {
|
||||
return;
|
||||
}
|
||||
|
||||
static const char *items[SHELL_MAX_APPS];
|
||||
static char names[SHELL_MAX_APPS][SHELL_APP_NAME_MAX + 16];
|
||||
int32_t count = 0;
|
||||
// 3 columns per row: Name, Type, Status
|
||||
static const char *cells[SHELL_MAX_APPS * 3];
|
||||
static char typeStrs[SHELL_MAX_APPS][12];
|
||||
int32_t rowCount = 0;
|
||||
|
||||
for (int32_t i = 1; i < SHELL_MAX_APPS; i++) {
|
||||
ShellAppT *app = shellGetApp(i);
|
||||
|
||||
if (app && app->state == AppStateRunningE) {
|
||||
const char *state = app->hasMainLoop ? "task" : "callback";
|
||||
snprintf(names[count], sizeof(names[count]), "%s [%s]", app->name, state);
|
||||
items[count] = names[count];
|
||||
count++;
|
||||
int32_t base = rowCount * 3;
|
||||
cells[base] = app->name;
|
||||
snprintf(typeStrs[rowCount], sizeof(typeStrs[rowCount]), "%s", app->hasMainLoop ? "Task" : "Callback");
|
||||
cells[base + 1] = typeStrs[rowCount];
|
||||
cells[base + 2] = "Running";
|
||||
rowCount++;
|
||||
}
|
||||
}
|
||||
|
||||
wgtListBoxSetItems(sTmListBox, items, count);
|
||||
wgtListViewSetData(sTmListView, cells, rowCount);
|
||||
}
|
||||
|
||||
|
||||
static void scanAppsDir(void) {
|
||||
DIR *dir = opendir("apps");
|
||||
sDxeCount = 0;
|
||||
scanAppsDirRecurse("apps");
|
||||
shellLog("Shell: found %ld app(s)", (long)sDxeCount);
|
||||
}
|
||||
|
||||
|
||||
static void scanAppsDirRecurse(const char *dirPath) {
|
||||
DIR *dir = opendir(dirPath);
|
||||
|
||||
if (!dir) {
|
||||
shellLog("Shell: apps/ directory not found");
|
||||
if (sDxeCount == 0) {
|
||||
shellLog("Shell: %s directory not found", dirPath);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sDxeCount = 0;
|
||||
struct dirent *ent;
|
||||
|
||||
while ((ent = readdir(dir)) != NULL && sDxeCount < MAX_DXE_FILES) {
|
||||
// Skip . and ..
|
||||
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char fullPath[MAX_PATH_LEN];
|
||||
snprintf(fullPath, sizeof(fullPath), "%s/%s", dirPath, ent->d_name);
|
||||
|
||||
// Check if this is a directory — recurse into it
|
||||
struct stat st;
|
||||
|
||||
if (stat(fullPath, &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||
scanAppsDirRecurse(fullPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
int32_t len = strlen(ent->d_name);
|
||||
|
||||
if (len < 5) {
|
||||
|
|
@ -428,12 +465,11 @@ static void scanAppsDir(void) {
|
|||
entry->name[0] -= 32;
|
||||
}
|
||||
|
||||
snprintf(entry->path, sizeof(entry->path), "apps/%s", ent->d_name);
|
||||
snprintf(entry->path, sizeof(entry->path), "%s", fullPath);
|
||||
sDxeCount++;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
shellLog("Shell: found %ld app(s)", (long)sDxeCount);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -167,6 +167,8 @@ DXE_EXPORT_TABLE(shellExportTable)
|
|||
DXE_EXPORT(wmSetIcon)
|
||||
DXE_EXPORT(wmCreateMenu)
|
||||
DXE_EXPORT(wmFreeMenu)
|
||||
DXE_EXPORT(wmUpdateContentRect)
|
||||
DXE_EXPORT(wmReallocContentBuf)
|
||||
|
||||
// dvxWidget.h — window integration
|
||||
DXE_EXPORT(wgtInitWindow)
|
||||
|
|
@ -278,6 +280,7 @@ DXE_EXPORT_TABLE(shellExportTable)
|
|||
// dvxWidget.h — canvas
|
||||
DXE_EXPORT(wgtCanvas)
|
||||
DXE_EXPORT(wgtCanvasClear)
|
||||
DXE_EXPORT(wgtCanvasSetMouseCallback)
|
||||
DXE_EXPORT(wgtCanvasSetPenColor)
|
||||
DXE_EXPORT(wgtCanvasSetPenSize)
|
||||
DXE_EXPORT(wgtCanvasSave)
|
||||
|
|
@ -301,6 +304,7 @@ DXE_EXPORT_TABLE(shellExportTable)
|
|||
// dvxWidget.h — operations
|
||||
DXE_EXPORT(wgtInvalidate)
|
||||
DXE_EXPORT(wgtInvalidatePaint)
|
||||
DXE_EXPORT(wgtSetDebugLayout)
|
||||
DXE_EXPORT(wgtSetText)
|
||||
DXE_EXPORT(wgtGetText)
|
||||
DXE_EXPORT(wgtSetEnabled)
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ static void logCrash(int sig) {
|
|||
|
||||
|
||||
// ============================================================
|
||||
// shellLog — append a line to SHELL.LOG
|
||||
// shellLog — append a line to DVX.LOG
|
||||
// ============================================================
|
||||
|
||||
void shellLog(const char *fmt, ...) {
|
||||
|
|
@ -163,7 +163,7 @@ void shellRegisterDesktopUpdate(void (*updateFn)(void)) {
|
|||
// ============================================================
|
||||
|
||||
int main(void) {
|
||||
sLogFile = fopen("shell.log", "w");
|
||||
sLogFile = fopen("dvx.log", "w");
|
||||
shellLog("DVX Shell starting...");
|
||||
|
||||
// Initialize GUI
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ DEMO_TARGET = $(BINDIR)/tsdemo.exe
|
|||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(TARGET) $(DEMO_TARGET)
|
||||
all: $(TARGET)
|
||||
|
||||
demo: $(DEMO_TARGET)
|
||||
|
||||
$(TARGET): $(OBJS) | $(LIBDIR)
|
||||
$(AR) rcs $@ $(OBJS)
|
||||
|
|
@ -52,4 +54,4 @@ $(OBJDIR)/taskswitch.o: taskswitch.c taskswitch.h thirdparty/stb_ds.h
|
|||
$(OBJDIR)/demo.o: demo.c taskswitch.h
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR) $(TARGET) $(DEMO_TARGET)
|
||||
rm -f $(OBJS) $(DEMO_OBJS) $(TARGET) $(DEMO_TARGET)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue