Hi,
Great questions. I'll address them the best I can..
Yes, you can run your own copy of the screenThe screen is not compiled into MachPro. It is a data file (a .set file) that is loaded at startup. The built-in workflow is exactly what you described:
- Load the shipped screen.
- Enter screen-edit mode.
- Use Screen → Save As and give it your own name (for example, MyMill.set).
- MachPro remembers that filename in your profile and loads your copy from then on. The shipped file is never touched.
- So the "fork" approach you are already used to works here too: maintain your own .set, take responsibility for merging changes if you ever do update, and keep the original as your fallback.
- Nothing in the user-code separation philosophy prevents this. That philosophy is about protecting you from updates, not about locking you out of the screen.
Your offsets, and those zero buttonsYour fixture offsets live on the Fixtures tab. That page exists for exactly the purpose you described: viewing and managing all the offsets that apply at a given moment.
And on the muscle-memory point: when you switch into Edit Offsets mode, Zero DRO buttons appear right next to each DRO. So the "zero button beside the DRO" workflow you're used to is already built into the screen. It only appears in that mode, deliberately, so an accidental tap during normal running can't zero an axis mid-job.
The Fixtures tab also has spare room and editable fields. If you want to rearrange it or add your own touches (extra readouts, your registration-hole button, and so on), it's a normal editable area in your forked copy, no workarounds needed.
Why some areas can't be editedThe reason you can add things outside the dashboard but can't change certain existing elements is that those areas (like the DRO block) are single, self-contained controls rather than groups of individually editable pieces. The editor can show them and let you attach code, but it can't let you rearrange what is inside them. There is nothing to grab onto.
The practical workaround where it matters: place your own buttons as separate controls overlapping or immediately adjacent to a sealed block, with your own code behind them. To the operator, the result looks and behaves the same as if the button were part of the block.
Screen editing tipsUse the UserGUIModule for behavior instead of (or alongside) the screen
If you haven't explored it yet, the UserGUIModule is your best friend for screen work. It lets you change what is displayed, switch pages, set labels, and adjust properties programmatically, which means you can often get what you want without editing the screen file at all. For example, forcing a specific page on a button press:
function UserGUIModule.MyCustomPage()
scr.ShowPage("CustomPageName")
end
--If you want the button in your dashboard.
function UserGUIModule.CreateUserCommands()
w.CreateCommandActionOption("ShowMyCustomPage", function(from_opr_panel) UserGUIModule.MyCustomPage() end)
w.CreateSimpleCommand("ShowMyCustomPage")
end
Alternatively, if you wanted to call anything from the UserGUIModule inside the screen with, lets say a custom button:
--Button Script
h.ScreenButtonCall(User.MyCustomPage(), ...)
Anything you can do with scr.SetProperty or scr.ShowPage in a module survives updates cleanly, because modules are user code and are never overwritten. A good strategy is: use Save As for layout changes you can't achieve any other way (button placement for muscle memory), and use the UserGUIModule for everything else (showing pages, relabeling, hiding and showing elements). That minimizes the diff in your forked screen and makes any future merge almost painless.
Why the self-contained controls are actually on your side
I understand the frustration, but the "hard-coded" composite controls exist for a reason. Actually several, and they all benefit you directly:
They can't be broken by screen edits. The DRO block contains logic that must always work: position display, units handling, work/machine coordinate switching. If its internals were exposed to the editor, one accidental drag in edit mode could silently break a safety-critical readout. You'd never know until you scrapped a part.
- They can't be broken by screen edits. The DRO block contains logic that must always work: position display, units handling, work/machine coordinate switching. If its internals were exposed to the editor, one accidental drag in edit mode could silently break a safety-critical readout. You'd never know until you scrapped a part.
- They come pre-automated. This is the big one, and it's easy to overlook if you're coming from Mach4. Much of what a Mach4 user had to hand-build, such as wiring buttons to function codes, scripting enable/disable behavior, linking LEDs to signals, and making DROs respond to units and coordinate modes, is already built into these controls. Drop a Cycle Start button on the screen and it works: no script, no signal plumbing, no PLC ladder. Anyone who set up a Mach4 screen from scratch knows how many evenings that used to take. MachPro's controls remove that startup burden. The screen is functional out of the box, and your time goes into the custom things your machine needs, not into re-implementing the basics.
- They survive updates. Because the control owns its own layout and behavior, a MachPro update can improve or fix the DRO block and your forked screen picks up the improvement automatically. The .set file just references the control; it doesn't freeze its internals.
- Your code still attaches to them. You can read their properties, react to their state, and build your own controls around them. They're sealed, not isolated.
In other words: the areas you can't edit are precisely the areas that either (a) would cost you parts if accidentally broken, or (b) would cost you evenings to rebuild if they weren't automated. The areas you can edit (pages, groups, dashboards, and your own buttons with your own code) are where all the productivity wins live anyway, and there the field is wide open.
Why custom buttons should use h.ScreenButtonCall()When you add your own button to the screen, its script property (for example, the Left Up Script) should call h.ScreenButtonCall(...) rather than calling your function directly. It is the standard entry point the shipped buttons use, and it gives your custom button the same protection and polish for free:
- Password protection is enforced automatically. If you set a password level on the button in the screen editor, ScreenButtonCall checks it before your code runs. No extra code in your handler, and no chance of an unauthorized operator triggering your function.
- Errors can't crash the screen. Your handler runs inside a protected wrapper. If your Lua code throws an error, you get a warning message instead of a dead UI.
- Every press is logged. The button's label and press are written to the log, which makes diagnosing "what did the operator do just before this happened" much easier.
- Standard argument handling. It passes your custom arguments first and the standard screen-event parameters (control name, event source, control type) last, so your handler signature stays consistent with every other button in the system.
The pattern looks like this in the button's script:
h.ScreenButtonCall(m.screen.MyCustomFunction, ...)Yes, multiple pages and tabs are supportedTabs are a first-class feature of the screen system. A dedicated Machine Diagnostics tab holding your live offsets block (and as many or as few I/O LEDs as you feel are worth the effort) is a completely normal thing to build. It costs zero space on the main page until you click over to it, which is exactly the behavior you described wanting. And with a scr.ShowPage("Diagnostics(1)") style call in the UserGUIModule, you can even jump to it from a button or a key rather than hunting for the tab.
One note before you build it: check the Fixtures tab first. Between its offsets display and Edit Offsets mode, it may already cover much of what your diagnostics page was doing, which would save you the rebuild.