DVX_GUI/apps/dvxbasic/ide/ideDesigner.h

226 lines
8.7 KiB
C

// ideDesigner.h -- DVX BASIC form designer
//
// Design-time data model and design surface for visual form editing.
// Controls are stored as pure data (not live widgets) and rendered
// onto a Canvas widget. The designer reads and writes .frm files.
#ifndef IDE_DESIGNER_H
#define IDE_DESIGNER_H
#include "dvxApp.h"
#include "dvxWgt.h"
#include "canvas/canvas.h"
#include "stb_ds_wrap.h"
#include <stdint.h>
#include <stdbool.h>
// ============================================================
// Limits
// ============================================================
#define DSGN_MAX_NAME 32
#define DSGN_MAX_TEXT 256
#define DSGN_MAX_PROPS 32
#define DSGN_MAX_FRM_NESTING 16
#define DSGN_GRID_SIZE 8
#define DSGN_HANDLE_SIZE 6
#define DSGN_MENU_ID_BASE 20000 // base ID for designer preview menu items
// ============================================================
// Design-time property (stored as key=value strings)
// ============================================================
typedef struct {
char name[DSGN_MAX_NAME];
char value[DSGN_MAX_TEXT];
} DsgnPropT;
// ============================================================
// Design-time menu item (flat array with level for tree structure)
// ============================================================
typedef struct {
char caption[DSGN_MAX_TEXT]; // "&File", "-" for separator
char name[DSGN_MAX_NAME]; // "mnuFile"
int32_t level; // 0 = top-level menu, 1 = item, 2+ = submenu
bool checked;
bool radioCheck; // true = radio bullet instead of checkmark
bool enabled; // default true
} DsgnMenuItemT;
// ============================================================
// Design-time control
// ============================================================
typedef struct {
char name[DSGN_MAX_NAME];
char typeName[DSGN_MAX_NAME];
char parentName[DSGN_MAX_NAME]; // empty = top-level (child of form)
int32_t index; // control array index (-1 = not in array)
int32_t left;
int32_t top;
int32_t width;
int32_t height;
int32_t maxWidth; // 0 = no cap (stretch to fill)
int32_t maxHeight; // 0 = no cap (stretch to fill)
int32_t weight; // layout weight (0 = fixed size, >0 = share extra space)
DsgnPropT props[DSGN_MAX_PROPS];
int32_t propCount;
WidgetT *widget; // live widget (created at design time for WYSIWYG)
} DsgnControlT;
// ============================================================
// Design-time form
// ============================================================
typedef struct {
char name[DSGN_MAX_NAME];
char caption[DSGN_MAX_TEXT];
int32_t width;
int32_t height;
int32_t left; // initial X position (0 = default)
int32_t top; // initial Y position (0 = default)
char layout[DSGN_MAX_NAME]; // "VBox" or "HBox" (contentBox type)
bool centered; // true = center on screen, false = use left/top
bool autoSize; // true = dvxFitWindow, false = use width/height
bool resizable; // true = user can resize at runtime
DsgnControlT **controls; // stb_ds array of heap-allocated pointers
DsgnMenuItemT *menuItems; // stb_ds dynamic array (NULL if no menus)
bool dirty;
WidgetT *contentBox; // VBox parent for live widgets
char *code; // BASIC code section (malloc'd, after End block)
} DsgnFormT;
// ============================================================
// Active tool
// ============================================================
//
// Empty string = pointer (select/move) mode.
// Non-empty = basName of the widget type to place.
#define DSGN_TOOL_NONE "" // pointer mode
// ============================================================
// Grab handle IDs
// ============================================================
typedef enum {
HANDLE_NONE = -1,
HANDLE_E = 0, // resize width
HANDLE_S, // resize height
HANDLE_SE, // resize both
HANDLE_COUNT = 3
} DsgnHandleE;
// ============================================================
// Interaction mode
// ============================================================
typedef enum {
DSGN_IDLE,
DSGN_REORDERING, // dragging control up/down in the VBox
DSGN_RESIZING
} DsgnModeE;
// ============================================================
// Designer state
// ============================================================
typedef struct {
DsgnFormT *form;
int32_t selectedIdx; // -1 = form itself selected
char activeTool[DSGN_MAX_NAME]; // "" = pointer, else basName to place
DsgnModeE mode;
DsgnHandleE activeHandle;
int32_t dragStartY; // mouse Y at drag start (for reorder)
int32_t dragOrigWidth; // widget size at resize start
int32_t dragOrigHeight;
int32_t dragStartX; // mouse X at resize start
WindowT *formWin;
AppContextT *ctx;
const char *projectDir; // project directory (for resolving relative paths)
} DsgnStateT;
// ============================================================
// API
// ============================================================
// Initialize designer state.
void dsgnInit(DsgnStateT *ds, AppContextT *ctx);
// Set the canvas overlay widget (for grab handles).
void dsgnSetCanvas(DsgnStateT *ds, WidgetT *canvas);
// Create live widgets for all controls in the form.
// Call after dsgnLoadFrm or dsgnNewForm, with the form window's contentBox.
void dsgnCreateWidgets(DsgnStateT *ds, WidgetT *contentBox);
// Load a .frm file into the designer.
bool dsgnLoadFrm(DsgnStateT *ds, const char *source, int32_t sourceLen);
// Save the designer form to .frm text format.
// Returns the number of bytes written (excluding null), or -1 on error.
int32_t dsgnSaveFrm(const DsgnStateT *ds, char *buf, int32_t bufSize);
// Create a new blank form.
void dsgnNewForm(DsgnStateT *ds, const char *name);
// Repaint the design surface.
void dsgnPaint(DsgnStateT *ds);
// Draw selection handles over the painted window surface.
void dsgnPaintOverlay(DsgnStateT *ds, int32_t winX, int32_t winY);
// Handle mouse click on the design surface.
void dsgnOnMouse(DsgnStateT *ds, int32_t x, int32_t y, bool drag);
// Handle key press in design view.
void dsgnOnKey(DsgnStateT *ds, int32_t key);
// Get the name of the selected control (or form name if nothing selected).
const char *dsgnSelectedName(const DsgnStateT *ds);
// Get the default event name for a control type.
const char *dsgnDefaultEvent(const char *typeName);
// Auto-generate a unique control name for the given type.
void dsgnAutoName(const DsgnStateT *ds, const char *typeName, char *buf, int32_t bufSize);
// Check if a control type is a container (can hold children).
bool dsgnIsContainer(const char *typeName);
// Free designer resources.
void dsgnFree(DsgnStateT *ds);
// Create a live design-time widget for a given VB type name.
WidgetT *dsgnCreateDesignWidget(const char *vbTypeName, WidgetT *parent);
// Build a display-only menu bar on a window from the form's menuItems.
// Used in the form designer to preview the menu layout.
void dsgnBuildPreviewMenuBar(WindowT *win, const DsgnFormT *form);
// Create a layout container (VBox/HBox/WrapBox) from a layout name string.
// For VBox, reuses the root directly. For HBox/WrapBox, creates a child.
WidgetT *dsgnCreateContentBox(WidgetT *root, const char *layout);
// Create and configure a window from form properties.
// Shared by the designer and runtime to ensure consistent behavior.
// Creates the window, widget root, and layout container (VBox/HBox/WrapBox).
// Applies sizing (autoSize or explicit) and positioning (centered or explicit).
// On success, sets *outRoot and *outContentBox and returns the window.
// On failure, returns NULL.
WindowT *dsgnCreateFormWindow(AppContextT *ctx, const char *title, const char *layout, bool resizable, bool centered, bool autoSize, int32_t width, int32_t height, int32_t left, int32_t top, WidgetT **outRoot, WidgetT **outContentBox);
// ============================================================
// Code rename support (implemented in ideMain.c)
// ============================================================
//
// Rename all references to a form or control in project .bas files.
// Replaces OldName. -> NewName. and OldName_ -> NewName_ (case-insensitive,
// word-boundary aware). Also handles FormName.ControlName. patterns.
void ideRenameInCode(const char *oldName, const char *newName);
#endif // IDE_DESIGNER_H