Two-Way Tools: Designer ↔ Code Sync
HarbourBuilder's Two-Way Tools engine ensures that your visual form design and your source code are always perfectly synchronized. Every change you make in the visual Form Designer is immediately reflected in the generated code, and every structural change you make to the code is instantly visible in the designer.
The code regeneration engine only updates UI definition lines (DEFINE, @ POSITION, properties). Your METHOD implementations, event handlers, and custom logic are never touched or overwritten.
How It Works
When you work in the Form Designer, every action — dropping a control, resizing, moving, changing a property — triggers a targeted code regeneration. The engine parses your existing source file, identifies the UI definition sections, updates them, and leaves everything else intact.
What Gets Regenerated
The code engine identifies and updates only these categories:
| Category | Example | Regenerated? |
|---|---|---|
| DEFINE statements | DEFINE FORM, DEFINE BUTTON | Yes |
| @ POSITION lines | @ 10, 20 BUTTON ... | Yes |
| Property assignments | ::cTitle := "Hello" | Yes |
| CLASS definitions | CLASS TForm1 FROM TForm | Yes |
| Control creation via code | TButton():New() | Yes |
| METHOD implementations | METHOD OnClick() CLASS TForm1 | No |
| Event handler bodies | bAction := { || ... } | No |
| Custom functions | static function MyHelper() | No |
| Comments | // TODO: ... | No |
Before and After: Code Regeneration
Before: You drop a button in the designer
CLASS TForm1 FROM TForm DATA oBtn1 METHOD CreateForm() METHOD OnBtnClick() ENDCLASS METHOD CreateForm() CLASS TForm1 ::cTitle := "Form1" ::nWidth := 400 ::nHeight := 300 return nil METHOD OnBtnClick() CLASS TForm1 // Your custom logic - PRESERVED MsgInfo( "Button clicked!" ) return nil
After: Code regenerated (button added, method untouched)
CLASS TForm1 FROM TForm DATA oBtn1 METHOD CreateForm() METHOD OnBtnClick() ENDCLASS METHOD CreateForm() CLASS TForm1 ::cTitle := "Form1" ::nWidth := 400 ::nHeight := 300 // --- NEW: Button added by designer --- @ 120, 140 BUTTON ::oBtn1 PROMPT "Button1" ; OF Self SIZE 120, 32 ; ACTION ::OnBtnClick() return nil METHOD OnBtnClick() CLASS TForm1 // Your custom logic - PRESERVED MsgInfo( "Button clicked!" ) return nil
The OnBtnClick method body is completely unchanged. Only the
CreateForm method received the new button definition.
Workflow
Code Parsing Rules
The regeneration engine uses these rules to identify safe-to-modify sections:
- CLASS / ENDCCLASS blocks — DATA and METHOD declarations are updated; existing METHOD bodies are skipped.
DEFINE FORMblocks — Properties within DEFINE blocks are regenerated.- @ POSITION statements — Position, size, and property clauses are updated.
ACTIVATE FORMblocks — Activation clauses are regenerated.- Everything else — Static functions, METHOD bodies, comments, and custom code are left untouched.
Keep your custom logic in separate METHOD implementations or static functions rather than inline within DEFINE blocks. This makes it easier for the regeneration engine to identify and preserve your code.
Handling Conflicts
If you manually edit a line that the designer also manages (e.g., changing a button's position in code while it's also on the form canvas), the designer's view takes precedence on the next regeneration. To avoid conflicts:
- Use the Object Inspector to change properties rather than editing code directly.
- Use the Designer canvas to move and resize controls.
- Use the Code Editor only for METHOD implementations, event handlers, and custom functions.
The regeneration engine has been tested with over 200 edge cases including nested DEFINE blocks, multiple forms in one file, mixed class-based and procedural syntax, and files with extensive comments.
Recent Improvements
The Two-Way Tools engine has been enhanced with several important improvements:
Improved Code Generation
- Automatic launcher placement: The
FUNCTION FormN()launcher is now placed at the very end of generated files, after user methods, to prevent duplicate function definitions. - Better method preservation: User method implementations are properly preserved during code regeneration cycles.
- Duplicate header stripping: Duplicate
#include "hbbuilder.ch"and#include "classes.prg"statements are automatically removed to prevent linker errors.
Build System Enhancements
- Separator stripping: "----" separators are automatically stripped from form files before assembly to prevent Harbour parse errors.
- Improved project loading: The
UI_FormCreateChildren()function ensures all deferred controls get proper Win32 handles after project loading.
New Property Support
- lTransparent for TLabel: Labels can now have transparent backgrounds, allowing form colors to show through.
- RGB() function: Added to
classes.prgfor creating color values from red, green, and blue components.
Switching Between Views
Use the toolbar toggle or keyboard shortcut to switch between Designer and Code views:
| Shortcut | Action |
|---|---|
| F12 | Toggle between Designer and Code views |
| Ctrl+Tab | Cycle through open editor tabs |
| Ctrl+S | Save (both design data and code) |