More IDE work.
This commit is contained in:
parent
7d74d76985
commit
59bc2b5ed3
7 changed files with 722 additions and 471 deletions
|
|
@ -3259,10 +3259,21 @@ static void updateCursorShape(AppContextT *ctx) {
|
|||
newCursor = CURSOR_RESIZE_V;
|
||||
}
|
||||
} else if (hitIdx >= 0 && hitPart == HIT_CONTENT) {
|
||||
// Hovering over content area -- check for ListView column border
|
||||
WindowT *win = ctx->stack.windows[hitIdx];
|
||||
|
||||
if (win->widgetRoot) {
|
||||
// Window-level cursor query (e.g. form designer handles)
|
||||
if (win->onCursorQuery) {
|
||||
int32_t cx = mx - win->x - win->contentX;
|
||||
int32_t cy = my - win->y - win->contentY;
|
||||
int32_t shape = win->onCursorQuery(win, cx, cy);
|
||||
|
||||
if (shape > 0) {
|
||||
newCursor = shape;
|
||||
}
|
||||
}
|
||||
|
||||
// Widget-level cursor query (e.g. ListView column border)
|
||||
if (newCursor == CURSOR_ARROW && win->widgetRoot) {
|
||||
int32_t cx = mx - win->x - win->contentX;
|
||||
int32_t cy = my - win->y - win->contentY;
|
||||
int32_t scrollX = win->hScroll ? win->hScroll->value : 0;
|
||||
|
|
|
|||
|
|
@ -555,6 +555,7 @@ typedef struct WindowT {
|
|||
void (*onClose)(struct WindowT *win);
|
||||
void (*onMenu)(struct WindowT *win, int32_t menuId);
|
||||
void (*onScroll)(struct WindowT *win, ScrollbarOrientE orient, int32_t value);
|
||||
int32_t (*onCursorQuery)(struct WindowT *win, int32_t x, int32_t y); // return CURSOR_* or 0 for default
|
||||
} WindowT;
|
||||
|
||||
// ============================================================
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -49,6 +49,7 @@ typedef struct {
|
|||
int32_t tabIndex;
|
||||
DsgnPropT props[DSGN_MAX_PROPS];
|
||||
int32_t propCount;
|
||||
WidgetT *widget; // live widget (created at design time for WYSIWYG)
|
||||
} DsgnControlT;
|
||||
|
||||
// ============================================================
|
||||
|
|
@ -62,6 +63,7 @@ typedef struct {
|
|||
int32_t height;
|
||||
DsgnControlT *controls; // stb_ds dynamic array
|
||||
bool dirty;
|
||||
WidgetT *contentBox; // VBox parent for live widgets
|
||||
} DsgnFormT;
|
||||
|
||||
// ============================================================
|
||||
|
|
@ -92,15 +94,10 @@ typedef enum {
|
|||
|
||||
typedef enum {
|
||||
HANDLE_NONE = -1,
|
||||
HANDLE_NW = 0,
|
||||
HANDLE_N,
|
||||
HANDLE_NE,
|
||||
HANDLE_E,
|
||||
HANDLE_SE,
|
||||
HANDLE_S,
|
||||
HANDLE_SW,
|
||||
HANDLE_W,
|
||||
HANDLE_COUNT = 8
|
||||
HANDLE_E = 0, // resize width
|
||||
HANDLE_S, // resize height
|
||||
HANDLE_SE, // resize both
|
||||
HANDLE_COUNT = 3
|
||||
} DsgnHandleE;
|
||||
|
||||
// ============================================================
|
||||
|
|
@ -109,9 +106,7 @@ typedef enum {
|
|||
|
||||
typedef enum {
|
||||
DSGN_IDLE,
|
||||
DSGN_PLACING,
|
||||
DSGN_DRAWING,
|
||||
DSGN_MOVING,
|
||||
DSGN_REORDERING, // dragging control up/down in the VBox
|
||||
DSGN_RESIZING
|
||||
} DsgnModeE;
|
||||
|
||||
|
|
@ -125,17 +120,11 @@ typedef struct {
|
|||
DsgnToolE activeTool;
|
||||
DsgnModeE mode;
|
||||
DsgnHandleE activeHandle;
|
||||
int32_t dragStartX;
|
||||
int32_t dragStartY;
|
||||
int32_t dragOrigLeft;
|
||||
int32_t dragOrigTop;
|
||||
int32_t dragOrigWidth;
|
||||
int32_t dragStartY; // mouse Y at drag start (for reorder)
|
||||
int32_t dragOrigWidth; // widget size at resize start
|
||||
int32_t dragOrigHeight;
|
||||
int32_t drawX; // rubber-band start for new control
|
||||
int32_t drawY;
|
||||
bool showGrid;
|
||||
bool snapToGrid;
|
||||
WidgetT *canvas;
|
||||
int32_t dragStartX; // mouse X at resize start
|
||||
WindowT *formWin;
|
||||
AppContextT *ctx;
|
||||
} DsgnStateT;
|
||||
|
||||
|
|
@ -146,9 +135,13 @@ typedef struct {
|
|||
// Initialize designer state.
|
||||
void dsgnInit(DsgnStateT *ds, AppContextT *ctx);
|
||||
|
||||
// Set the canvas widget for rendering.
|
||||
// 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);
|
||||
|
||||
|
|
@ -162,6 +155,9 @@ 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,15 +8,16 @@
|
|||
// work on real hardware inside the DVX windowing system.
|
||||
|
||||
#include "dvxApp.h"
|
||||
#include "dvxCursor.h"
|
||||
#include "dvxDialog.h"
|
||||
#include "dvxWidget.h"
|
||||
#include "dvxWidgetPlugin.h"
|
||||
#include "dvxWm.h"
|
||||
#include "shellApp.h"
|
||||
#include "widgetBox.h"
|
||||
#include "widgetLabel.h"
|
||||
#include "widgetTextInput.h"
|
||||
#include "widgetDropdown.h"
|
||||
#include "widgetCanvas.h"
|
||||
#include "widgetSplitter.h"
|
||||
#include "widgetStatusBar.h"
|
||||
|
||||
|
|
@ -89,7 +90,9 @@ static void onFormWinClose(WindowT *win);
|
|||
static void setStatus(const char *text);
|
||||
static void switchToCode(void);
|
||||
static void switchToDesign(void);
|
||||
static void dsgnMouseCb(WidgetT *w, int32_t cx, int32_t cy, bool drag);
|
||||
static int32_t onFormWinCursorQuery(WindowT *win, int32_t x, int32_t y);
|
||||
static void onFormWinMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons);
|
||||
static void onFormWinPaint(WindowT *win, RectT *dirtyArea);
|
||||
static void updateDropdowns(void);
|
||||
|
||||
// ============================================================
|
||||
|
|
@ -753,6 +756,13 @@ static void loadFile(void) {
|
|||
snprintf(title, sizeof(title), "DVX BASIC - %s", path);
|
||||
dvxSetTitle(sAc, sWin, title);
|
||||
|
||||
// Close any open form designer and clear cached form
|
||||
if (sFormWin) {
|
||||
onFormWinClose(sFormWin);
|
||||
}
|
||||
|
||||
dsgnFree(&sDesigner);
|
||||
|
||||
updateDropdowns();
|
||||
setStatus("File loaded.");
|
||||
}
|
||||
|
|
@ -1074,13 +1084,118 @@ static void printCallback(void *ctx, const char *text, bool newline) {
|
|||
}
|
||||
|
||||
// ============================================================
|
||||
// dsgnMouseCb
|
||||
// onFormWinMouse
|
||||
// ============================================================
|
||||
//
|
||||
// Handle mouse events on the form designer window. Coordinates
|
||||
// are relative to the window's client area (content box origin).
|
||||
|
||||
// ============================================================
|
||||
// onFormWinCursorQuery
|
||||
// ============================================================
|
||||
|
||||
static void dsgnMouseCb(WidgetT *w, int32_t cx, int32_t cy, bool drag) {
|
||||
(void)w;
|
||||
dsgnOnMouse(&sDesigner, cx, cy, drag);
|
||||
prpRefresh(&sDesigner);
|
||||
static int32_t onFormWinCursorQuery(WindowT *win, int32_t x, int32_t y) {
|
||||
(void)win;
|
||||
|
||||
if (!sDesigner.form || !sDesigner.form->controls) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t count = (int32_t)arrlen(sDesigner.form->controls);
|
||||
|
||||
if (sDesigner.selectedIdx < 0 || sDesigner.selectedIdx >= count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
DsgnControlT *ctrl = &sDesigner.form->controls[sDesigner.selectedIdx];
|
||||
|
||||
if (!ctrl->widget || ctrl->widget->w <= 0 || ctrl->widget->h <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t cx = ctrl->widget->x;
|
||||
int32_t cy = ctrl->widget->y;
|
||||
int32_t cw = ctrl->widget->w;
|
||||
int32_t ch = ctrl->widget->h;
|
||||
int32_t hs = DSGN_HANDLE_SIZE;
|
||||
|
||||
// SE handle (check first -- overlaps with E and S)
|
||||
if (x >= cx + cw - hs/2 && x < cx + cw + hs/2 && y >= cy + ch - hs/2 && y < cy + ch + hs/2) {
|
||||
return CURSOR_RESIZE_DIAG_NWSE;
|
||||
}
|
||||
|
||||
// E handle (right edge center)
|
||||
if (x >= cx + cw - hs/2 && x < cx + cw + hs/2 && y >= cy + ch/2 - hs/2 && y < cy + ch/2 + hs/2) {
|
||||
return CURSOR_RESIZE_H;
|
||||
}
|
||||
|
||||
// S handle (bottom center)
|
||||
if (x >= cx + cw/2 - hs/2 && x < cx + cw/2 + hs/2 && y >= cy + ch - hs/2 && y < cy + ch + hs/2) {
|
||||
return CURSOR_RESIZE_V;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void onFormWinMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) {
|
||||
(void)win;
|
||||
static int32_t lastButtons = 0;
|
||||
bool wasDown = (lastButtons & MOUSE_LEFT) != 0;
|
||||
bool isDown = (buttons & MOUSE_LEFT) != 0;
|
||||
|
||||
if (!sDesigner.form || !sFormWin) {
|
||||
lastButtons = buttons;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDown) {
|
||||
bool drag = wasDown;
|
||||
dsgnOnMouse(&sDesigner, x, y, drag);
|
||||
prpRefresh(&sDesigner);
|
||||
|
||||
if (sFormWin) {
|
||||
dvxInvalidateWindow(sAc, sFormWin);
|
||||
}
|
||||
} else if (wasDown) {
|
||||
dsgnOnMouse(&sDesigner, x, y, false);
|
||||
prpRefresh(&sDesigner);
|
||||
|
||||
if (sFormWin) {
|
||||
dvxInvalidateWindow(sAc, sFormWin);
|
||||
}
|
||||
}
|
||||
|
||||
lastButtons = buttons;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// onFormWinPaint
|
||||
// ============================================================
|
||||
//
|
||||
// Draw selection handles after widgets have painted.
|
||||
|
||||
static void onFormWinPaint(WindowT *win, RectT *dirtyArea) {
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Force a full measure + layout + paint cycle.
|
||||
// widgetOnPaint normally skips relayout if root dimensions haven't
|
||||
// changed, but we need it to pick up minH changes from handle drag.
|
||||
if (win->widgetRoot) {
|
||||
widgetCalcMinSizeTree(win->widgetRoot, &sAc->font);
|
||||
win->widgetRoot->w = 0; // force layout pass to re-run
|
||||
}
|
||||
|
||||
widgetOnPaint(win, dirtyArea);
|
||||
|
||||
// Then draw selection handles on top
|
||||
int32_t winX = win->contentX;
|
||||
int32_t winY = win->contentY;
|
||||
|
||||
dsgnPaintOverlay(&sDesigner, winX, winY);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1091,7 +1206,7 @@ static void dsgnMouseCb(WidgetT *w, int32_t cx, int32_t cy, bool drag) {
|
|||
static void onFormWinClose(WindowT *win) {
|
||||
dvxDestroyWindow(sAc, win);
|
||||
sFormWin = NULL;
|
||||
dsgnSetCanvas(&sDesigner, NULL);
|
||||
sDesigner.formWin = NULL;
|
||||
|
||||
if (sToolboxWin) {
|
||||
tbxDestroy(sAc, sToolboxWin);
|
||||
|
|
@ -1168,31 +1283,42 @@ static void switchToDesign(void) {
|
|||
}
|
||||
}
|
||||
|
||||
// Create the form designer window
|
||||
// Create the form designer window (same size as runtime)
|
||||
const char *formName = sDesigner.form ? sDesigner.form->name : "Form1";
|
||||
int32_t formW = sDesigner.form ? sDesigner.form->width : IDE_DESIGN_W;
|
||||
int32_t formH = sDesigner.form ? sDesigner.form->height : IDE_DESIGN_H;
|
||||
|
||||
char title[128];
|
||||
snprintf(title, sizeof(title), "%s [Design]", formName);
|
||||
|
||||
// Position next to the IDE window
|
||||
int32_t winX = IDE_WIN_X;
|
||||
int32_t winY = IDE_WIN_Y;
|
||||
|
||||
sFormWin = dvxCreateWindow(sAc, title, winX, winY, formW + 10, formH + 10, true);
|
||||
sFormWin = dvxCreateWindowCentered(sAc, title, IDE_DESIGN_W, IDE_DESIGN_H, true);
|
||||
|
||||
if (!sFormWin) {
|
||||
return;
|
||||
}
|
||||
|
||||
sFormWin->onClose = onFormWinClose;
|
||||
sFormWin->onClose = onFormWinClose;
|
||||
sDesigner.formWin = sFormWin;
|
||||
|
||||
WidgetT *root = wgtInitWindow(sAc, sFormWin);
|
||||
WidgetT *canvas = wgtCanvas(root, formW, formH);
|
||||
canvas->weight = 100;
|
||||
wgtCanvasSetMouseCallback(canvas, dsgnMouseCb);
|
||||
dsgnSetCanvas(&sDesigner, canvas);
|
||||
WidgetT *root = wgtInitWindow(sAc, sFormWin);
|
||||
WidgetT *contentBox = wgtVBox(root);
|
||||
contentBox->weight = 100;
|
||||
|
||||
// Override paint and mouse AFTER wgtInitWindow (which sets widgetOnPaint)
|
||||
sFormWin->onPaint = onFormWinPaint;
|
||||
sFormWin->onMouse = onFormWinMouse;
|
||||
sFormWin->onCursorQuery = onFormWinCursorQuery;
|
||||
|
||||
// Create live widgets for each control
|
||||
dsgnCreateWidgets(&sDesigner, contentBox);
|
||||
|
||||
// Set form caption as window title
|
||||
if (sDesigner.form && sDesigner.form->caption[0]) {
|
||||
char winTitle[280];
|
||||
snprintf(winTitle, sizeof(winTitle), "%s [Design]", sDesigner.form->caption);
|
||||
dvxSetTitle(sAc, sFormWin, winTitle);
|
||||
}
|
||||
|
||||
// Shrink-wrap the window to its content (matches runtime behavior)
|
||||
dvxFitWindow(sAc, sFormWin);
|
||||
|
||||
// Create toolbox and properties windows
|
||||
if (!sToolboxWin) {
|
||||
|
|
@ -1203,7 +1329,6 @@ static void switchToDesign(void) {
|
|||
sPropsWin = prpCreate(sAc, &sDesigner);
|
||||
}
|
||||
|
||||
dsgnPaint(&sDesigner);
|
||||
setStatus("Design view open.");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
// ideProperties.c -- DVX BASIC form designer properties window
|
||||
//
|
||||
// A floating window with a two-column list showing property names
|
||||
// and values for the currently selected control. Double-clicking
|
||||
// a value opens an input dialog to edit it.
|
||||
// A floating window with a TreeView listing all controls on the
|
||||
// form (for selection and drag-reorder) and a read-only TextArea
|
||||
// showing properties of the selected control.
|
||||
|
||||
#include "ideProperties.h"
|
||||
#include "dvxDialog.h"
|
||||
#include "dvxWm.h"
|
||||
#include "widgetBox.h"
|
||||
#include "widgetLabel.h"
|
||||
#include "widgetTextInput.h"
|
||||
#include "widgetTreeView.h"
|
||||
#include "widgetSplitter.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -21,23 +22,25 @@
|
|||
// ============================================================
|
||||
|
||||
#define PRP_WIN_W 200
|
||||
#define PRP_WIN_H 320
|
||||
#define PRP_MAX_ROWS 64
|
||||
#define PRP_WIN_H 340
|
||||
|
||||
// ============================================================
|
||||
// Module state
|
||||
// ============================================================
|
||||
|
||||
static DsgnStateT *sDs = NULL;
|
||||
static WindowT *sPrpWin = NULL;
|
||||
static WidgetT *sListArea = NULL; // TextArea showing properties as text
|
||||
static AppContextT *sPrpCtx = NULL;
|
||||
static DsgnStateT *sDs = NULL;
|
||||
static WindowT *sPrpWin = NULL;
|
||||
static WidgetT *sTree = NULL;
|
||||
static WidgetT *sPropsArea = NULL;
|
||||
static AppContextT *sPrpCtx = NULL;
|
||||
static bool sUpdating = false; // prevent feedback loops
|
||||
|
||||
// ============================================================
|
||||
// Prototypes
|
||||
// ============================================================
|
||||
|
||||
static void onPrpClose(WindowT *win);
|
||||
static void onTreeChange(WidgetT *w);
|
||||
|
||||
// ============================================================
|
||||
// onPrpClose
|
||||
|
|
@ -48,6 +51,111 @@ static void onPrpClose(WindowT *win) {
|
|||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// onTreeChange
|
||||
// ============================================================
|
||||
//
|
||||
// Called when the TreeView selection changes or when items are
|
||||
// reordered by drag. Sync the designer state from the tree.
|
||||
|
||||
static void onTreeChange(WidgetT *w) {
|
||||
(void)w;
|
||||
|
||||
if (!sDs || !sDs->form || !sTree || sUpdating) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find which tree item is selected and map to control index
|
||||
int32_t count = (int32_t)arrlen(sDs->form->controls);
|
||||
int32_t selIdx = -1;
|
||||
|
||||
// Iterate tree items (children of sTree) to find the selected one
|
||||
int32_t idx = 0;
|
||||
|
||||
for (WidgetT *item = sTree->firstChild; item; item = item->nextSibling, idx++) {
|
||||
if (wgtTreeItemIsSelected(item)) {
|
||||
selIdx = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the tree order differs from the design array
|
||||
// (drag-reorder happened). If so, rebuild the array to match.
|
||||
bool reordered = false;
|
||||
idx = 0;
|
||||
|
||||
for (WidgetT *item = sTree->firstChild; item; item = item->nextSibling, idx++) {
|
||||
if (idx >= count) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Each tree item's userData stores the control name
|
||||
const char *itemName = (const char *)item->userData;
|
||||
|
||||
if (itemName && strcmp(itemName, sDs->form->controls[idx].name) != 0) {
|
||||
reordered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (reordered) {
|
||||
// Rebuild the controls array to match tree order
|
||||
DsgnControlT *newArr = NULL;
|
||||
idx = 0;
|
||||
|
||||
for (WidgetT *item = sTree->firstChild; item; item = item->nextSibling) {
|
||||
const char *itemName = (const char *)item->userData;
|
||||
|
||||
if (!itemName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find this control in the original array
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
if (strcmp(sDs->form->controls[i].name, itemName) == 0) {
|
||||
arrput(newArr, sDs->form->controls[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the controls array
|
||||
arrfree(sDs->form->controls);
|
||||
sDs->form->controls = newArr;
|
||||
sDs->form->dirty = true;
|
||||
|
||||
// Rebuild live widgets in new order
|
||||
if (sDs->form->contentBox) {
|
||||
sDs->form->contentBox->firstChild = NULL;
|
||||
sDs->form->contentBox->lastChild = NULL;
|
||||
|
||||
int32_t newCount = (int32_t)arrlen(sDs->form->controls);
|
||||
|
||||
for (int32_t i = 0; i < newCount; i++) {
|
||||
sDs->form->controls[i].widget = NULL;
|
||||
}
|
||||
|
||||
dsgnCreateWidgets(sDs, sDs->form->contentBox);
|
||||
}
|
||||
|
||||
// Update selection to match tree
|
||||
count = (int32_t)arrlen(sDs->form->controls);
|
||||
}
|
||||
|
||||
// Update designer selection
|
||||
if (selIdx != sDs->selectedIdx) {
|
||||
sDs->selectedIdx = selIdx;
|
||||
|
||||
if (sDs->formWin) {
|
||||
dvxInvalidateWindow(sPrpCtx, sDs->formWin);
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh properties display
|
||||
prpRefresh(sDs);
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// prpCreate
|
||||
// ============================================================
|
||||
|
|
@ -56,7 +164,6 @@ WindowT *prpCreate(AppContextT *ctx, DsgnStateT *ds) {
|
|||
sDs = ds;
|
||||
sPrpCtx = ctx;
|
||||
|
||||
// Position at right edge of screen
|
||||
int32_t winX = ctx->display.width - PRP_WIN_W - 10;
|
||||
WindowT *win = dvxCreateWindow(ctx, "Properties", winX, 30, PRP_WIN_W, PRP_WIN_H, false);
|
||||
|
||||
|
|
@ -69,10 +176,18 @@ WindowT *prpCreate(AppContextT *ctx, DsgnStateT *ds) {
|
|||
|
||||
WidgetT *root = wgtInitWindow(ctx, win);
|
||||
|
||||
// Properties displayed as a read-only text area (simple approach)
|
||||
sListArea = wgtTextArea(root, 4096);
|
||||
sListArea->weight = 100;
|
||||
sListArea->readOnly = true;
|
||||
// Splitter: tree on top, properties on bottom
|
||||
WidgetT *splitter = wgtSplitter(root, false);
|
||||
splitter->weight = 100;
|
||||
|
||||
// Control tree (top pane)
|
||||
sTree = wgtTreeView(splitter);
|
||||
sTree->onChange = onTreeChange;
|
||||
wgtTreeViewSetReorderable(sTree, true);
|
||||
|
||||
// Properties text (bottom pane)
|
||||
sPropsArea = wgtTextArea(splitter, 4096);
|
||||
sPropsArea->readOnly = true;
|
||||
|
||||
prpRefresh(ds);
|
||||
return win;
|
||||
|
|
@ -88,9 +203,10 @@ void prpDestroy(AppContextT *ctx, WindowT *win) {
|
|||
dvxDestroyWindow(ctx, win);
|
||||
}
|
||||
|
||||
sPrpWin = NULL;
|
||||
sListArea = NULL;
|
||||
sDs = NULL;
|
||||
sPrpWin = NULL;
|
||||
sTree = NULL;
|
||||
sPropsArea = NULL;
|
||||
sDs = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -99,7 +215,38 @@ void prpDestroy(AppContextT *ctx, WindowT *win) {
|
|||
// ============================================================
|
||||
|
||||
void prpRefresh(DsgnStateT *ds) {
|
||||
if (!sListArea || !ds || !ds->form) {
|
||||
if (!ds || !ds->form) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Rebuild tree items
|
||||
if (sTree) {
|
||||
sUpdating = true;
|
||||
|
||||
// Clear existing tree items
|
||||
sTree->firstChild = NULL;
|
||||
sTree->lastChild = NULL;
|
||||
|
||||
int32_t count = (int32_t)arrlen(ds->form->controls);
|
||||
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
DsgnControlT *ctrl = &ds->form->controls[i];
|
||||
char label[128];
|
||||
snprintf(label, sizeof(label), "%s (%s)", ctrl->name, ctrl->typeName);
|
||||
|
||||
WidgetT *item = wgtTreeItem(sTree, label);
|
||||
item->userData = ctrl->name; // store name for reorder tracking
|
||||
|
||||
if (i == ds->selectedIdx) {
|
||||
wgtTreeItemSetSelected(item, true);
|
||||
}
|
||||
}
|
||||
|
||||
sUpdating = false;
|
||||
}
|
||||
|
||||
// Update properties text
|
||||
if (!sPropsArea) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -109,11 +256,8 @@ void prpRefresh(DsgnStateT *ds) {
|
|||
if (ds->selectedIdx >= 0 && ds->selectedIdx < (int32_t)arrlen(ds->form->controls)) {
|
||||
DsgnControlT *ctrl = &ds->form->controls[ds->selectedIdx];
|
||||
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "%s (%s)\n", ctrl->name, ctrl->typeName);
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "---\n");
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "Name = %s\n", ctrl->name);
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "Left = %d\n", (int)ctrl->left);
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "Top = %d\n", (int)ctrl->top);
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "Type = %s\n", ctrl->typeName);
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "Width = %d\n", (int)ctrl->width);
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "Height = %d\n", (int)ctrl->height);
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "TabIndex = %d\n", (int)ctrl->tabIndex);
|
||||
|
|
@ -123,12 +267,10 @@ void prpRefresh(DsgnStateT *ds) {
|
|||
}
|
||||
} else {
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "%s (Form)\n", ds->form->name);
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "---\n");
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "Name = %s\n", ds->form->name);
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "Caption = %s\n", ds->form->caption);
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "Width = %d\n", (int)ds->form->width);
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, "Height = %d\n", (int)ds->form->height);
|
||||
}
|
||||
|
||||
wgtSetText(sListArea, buf);
|
||||
wgtSetText(sPropsArea, buf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ static void onToolClick(WidgetT *w) {
|
|||
|
||||
if (toolIdx >= 0 && toolIdx < TOOL_COUNT) {
|
||||
sDs->activeTool = (DsgnToolE)toolIdx;
|
||||
sDs->mode = (toolIdx == TOOL_POINTER) ? DSGN_IDLE : DSGN_PLACING;
|
||||
sDs->mode = DSGN_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue