0.8.0: version, README and site (what's new, three icons); the new commands in the menus too (history, select similar/loop/ring, spin, crease, slide, mirror editing, measure, workspaces, text, search), with your own keys shown; plug-in tools finger-sized on phones

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nexoniarz 2026-10-21 08:56:51 +02:00
commit 3c819146af
6 changed files with 80 additions and 19 deletions

View file

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25) cmake_minimum_required(VERSION 3.25)
project(Fry3DX VERSION 0.7.0 LANGUAGES C CXX) project(Fry3DX VERSION 0.8.0 LANGUAGES C CXX)
set(CMAKE_CXX_SCAN_FOR_MODULES OFF) # (no C++ modules; the scan can pick up a different clang than the NDK's) set(CMAKE_CXX_SCAN_FOR_MODULES OFF) # (no C++ modules; the scan can pick up a different clang than the NDK's)
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
add_link_options(-rdynamic) # function names in crash reports add_link_options(-rdynamic) # function names in crash reports

View file

@ -39,6 +39,12 @@ comes inside the app (MoltenVK, on Metal), and OpenGL 4.1 is the fallback.
Five tabs along the top: **Model**, **Paint**, **Layout**, **Render**, **Print** (Ctrl+1 to 5). Five tabs along the top: **Model**, **Paint**, **Layout**, **Render**, **Print** (Ctrl+1 to 5).
**Finding things**
- **Any command by name**: F3 or Ctrl+Space, type a few letters. **Round the mouse**: hold Space
for the tools, Shift+Space for the views. Give any command **your own key** (Help > Keys and
mouse). **Undo history** (Edit > Undo history): go back to any step. **Workspaces**: the panels as
you had them, kept under a name.
**Making shapes** **Making shapes**
- **Shapes that stay editable**: cube, rounded cube, plane, circle, cylinder, tube, cone, pyramid, - **Shapes that stay editable**: cube, rounded cube, plane, circle, cylinder, tube, cone, pyramid,
sphere, capsule, torus, wedge, stairs, arch, and starter models (table, chair, shelf, barrel, sphere, capsule, torus, wedge, stairs, arch, and starter models (table, chair, shelf, barrel,
@ -46,7 +52,13 @@ Five tabs along the top: **Model**, **Paint**, **Layout**, **Render**, **Print**
- **Draw shape** (D): click an outline on the ground, on a side view's plane, or straight on any - **Draw shape** (D): click an outline on the ground, on a side view's plane, or straight on any
face of another object: a new part standing on it, added to it, or cut into it. face of another object: a new part standing on it, added to it, or cut into it.
- **Move, turn, scale** (W, E, R): the arrows turn with the object. Scale keeps the other side - **Move, turn, scale** (W, E, R): the arrows turn with the object. Scale keeps the other side
where it is; Shift scales both sides at once. Ctrl snaps. where it is; Shift scales both sides at once. Ctrl snaps: to steps, or to points and the middles
of edges and faces.
- **Exact sizes**: type a number while dragging (move, turn, scale, extrude, inset, round edges)
and Enter for exactly that. Dimensions in Properties; measure anything (View > Measure). Drawing
a shape shows each line's length: type one for exactly that, Shift holds it to 15° steps.
- **3D text** from any font (Add > Text). **Spin**: an outline turned round an axis into a vase or
a wheel, or rising into a screw thread. **Import** STL, OBJ, 3MF, glTF and GLB (Ctrl+Shift+O).
- **Round, smooth, mirror** any object, changeable any time, baked in when you like. - **Round, smooth, mirror** any object, changeable any time, baked in when you like.
- **Materials**: gold, chrome, steel, wood, ceramic, rubber and more, or how metal and rough it - **Materials**: gold, chrome, steel, wood, ceramic, rubber and more, or how metal and rough it
is; shown in the view (Solid too), exported with it. **Your own**: "Save its look as a is; shown in the view (Solid too), exported with it. **Your own**: "Save its look as a
@ -55,7 +67,9 @@ Five tabs along the top: **Model**, **Paint**, **Layout**, **Render**, **Print**
**Editing the shape** (Tab, or double-click) **Editing the shape** (Tab, or double-click)
- Points, edges, faces (1, 2, 3). Extrude (X), inset (I), round edges (B), loop cut (C), knife (K), - Points, edges, faces (1, 2, 3). Extrude (X), inset (I), round edges (B), loop cut (C), knife (K),
cut in four, smooth, merge (M), make a face, flip, separate (P), smooth points, push out / cut in four, smooth, merge (M), make a face, flip, separate (P), smooth points, push out /
pull in along the surface (Alt+S), **bridge** two faces with a tunnel. pull in along the surface (Alt+S), **bridge** two faces with a tunnel, **edge slide** (Alt+G).
- **Crease** (Shift+E): picked edges stay sharp when the shape is smoothed. **Mirror editing**:
both sides change together. **Select similar** (Shift+G), loops and rings.
- **Soft selection** (Shift+O): points near what you move follow it, less the further they are; - **Soft selection** (Shift+O): points near what you move follow it, less the further they are;
the wheel while dragging sets how far (Blender's proportional editing, Maya's soft select). the wheel while dragging sets how far (Blender's proportional editing, Maya's soft select).
- **Hole** (O): round (M2–M8 screw sizes ready), rectangle, triangle or hexagon (M2–M8 nut - **Hole** (O): round (M2–M8 screw sizes ready), rectangle, triangle or hexagon (M2–M8 nut
@ -64,9 +78,12 @@ Five tabs along the top: **Model**, **Paint**, **Layout**, **Render**, **Print**
edge's ring, Ctrl+click adds or takes one. edge's ring, Ctrl+click adds or takes one.
**Whole objects** (the Object menu) **Whole objects** (the Object menu)
- **Add together, take one out of another, keep only where they overlap**: always closed, so - **Add together, take one out of another, keep only where they overlap**: exact
always printable (Ctrl+Shift+ and Ctrl+Shift−). ([Manifold](https://github.com/elalish/manifold)) and always closed, so always printable
- **Copies** in a row or round a circle; **make it thick** (a surface gets a back, a solid goes (Ctrl+Shift+ and Ctrl+Shift−).
- **Cut out, editable**: the cutters stay objects. Move one, turn it, change its shape, and the
hole follows; they go with what they cut. Apply makes it for good.
- **Copies** in a row, round a circle, or **along a path** (turning as it turns); **make it thick** (a surface gets a back, a solid goes
hollow); join objects; join flat faces. hollow); join objects; join flat faces.
- **Layers** with folders inside folders, drag and drop, hide and lock whole groups, and a button - **Layers** with folders inside folders, drag and drop, hide and lock whole groups, and a button
on every row that brings the camera to it. **Show only the selected** (/ or Shift+H; again: on every row that brings the camera to it. **Show only the selected** (/ or Shift+H; again:
@ -78,7 +95,8 @@ Five tabs along the top: **Model**, **Paint**, **Layout**, **Render**, **Print**
keeping its shape. keeping its shape.
**Painting** **Painting**
- Paint on the model or on its flat picture. **Paste any picture** (Ctrl+V): it goes on like a - Paint on the model or on its flat picture, on **both sides** at once, or only inside a
**stencil** you drag round an area. **Paste any picture** (Ctrl+V): it goes on like a
sticker that bends over edges and corners; Enter locks it as a layer, clicking it in the sticker that bends over edges and corners; Enter locks it as a layer, clicking it in the
Picture panel unlocks it again. Picture panel unlocks it again.
- **Layout tab**: move, turn and size the flat frames of the surface yourself; the paint follows. - **Layout tab**: move, turn and size the flat frames of the surface yourself; the paint follows.
@ -87,11 +105,16 @@ Five tabs along the top: **Model**, **Paint**, **Layout**, **Render**, **Print**
- **Solid** view for modelling, **Rendered** with a real sky, sun and soft shadows (Z). Wireframe - **Solid** view for modelling, **Rendered** with a real sky, sun and soft shadows (Z). Wireframe
(Shift+Z), X-ray (Alt+Z). The Render tab: the sun, sky, ground, brightness, shadows, glow; (Shift+Z), X-ray (Alt+Z). The Render tab: the sun, sky, ground, brightness, shadows, glow;
F12 saves a picture of just the view. F12 saves a picture of just the view.
- **Reference pictures** for the front, side and top views, see-through, shown only in their own
view if you like.
**3D printing** (the Print tab) **3D printing** (the Print tab)
- Your printer's plate in the view (Prusa, Bambu, Creality, Elegoo, Anycubic, or your own), - Your printer's plate in the view (Prusa, Bambu, Creality, Elegoo, Anycubic, or your own),
sizes in millimetres, checks for holes and flipped faces with buttons that fix them, overhangs sizes in millimetres, checks for holes and flipped faces with **one repair button**, overhangs
in red, weight and filament, measuring, lay flat on a face, save 3MF or STL. in red, **walls too thin** in yellow, weight and filament, measuring, lay flat on a face, save
3MF or STL.
- **Size it**: by percent, ×½, ×2, inches or centimetres to millimetres, or as big as fits the
plate. **Slice preview**: one layer as the printer makes it, at any layer height.
**Scripts** (the Script panel, F5) **Scripts** (the Script panel, F5)
- Lua with a `fry` library: add shapes and change their settings, combine them, move points by a - Lua with a `fry` library: add shapes and change their settings, combine them, move points by a
@ -106,7 +129,10 @@ Five tabs along the top: **Model**, **Paint**, **Layout**, **Render**, **Print**
- Scripts that stay loaded: put a `.lua` in the plug-ins folder and it can add **commands to the - Scripts that stay loaded: put a `.lua` in the plug-ins folder and it can add **commands to the
Add, Object or Script menu** (`fry.command{name, menu, settings, run}`; the settings are asked Add, Object or Script menu** (`fry.command{name, menu, settings, run}`; the settings are asked
for in a small form first) and **materials** to the picker. Turn each on or off in the Plug-ins for in a small form first) and **materials** to the picker. Turn each on or off in the Plug-ins
window. Three come with it: stairs (straight and spiral), scatter copies, and more materials. window, look for one, or make your own copy of one to change. **Mouse tools** too
(`fry.tool{name, click}`): listed in the Toolbox, a click in the view calls it with the spot.
Four come with it: stairs (straight and spiral), scatter copies, stamp (a mouse tool), and more
materials.
```lua ```lua
fry.plugin{name = "Shelves", about = "A bookcase from the Add menu"} fry.plugin{name = "Shelves", about = "A bookcase from the Add menu"}
@ -130,7 +156,8 @@ fry.command{name = "Bookcase", menu = "add", settings = {{"shelves", 5}, {"width
**On a phone or tablet**: everything bigger, the side panels when you want them, a bar of big **On a phone or tablet**: everything bigger, the side panels when you want them, a bar of big
buttons (undo, redo, Shift and Ctrl that stay down, edit the shape, delete, frame). One finger buttons (undo, redo, Shift and Ctrl that stay down, edit the shape, delete, frame). One finger
turns the view (or drags the arrows), two fingers move it and pinch to zoom, holding a finger turns the view (or drags the arrows), two fingers move it and pinch to zoom, holding a finger
still is a right-click. Files open and save through the phone's own file picker. still is a right-click. Files open and save through the phone's own file picker. It stays
sideways, and going to another app and back keeps your work.
F1 in the app lists every key. F1 in the app lists every key.

View file

@ -29,20 +29,24 @@ window.FRY = {
features: [ features: [
{ group: "make", icon: "cube", title: "Shapes that stay editable", text: "Cube, cylinder, sphere, torus, stairs, arch and more, plus starter models like a table, chair or barrel. Change their sizes any time in Properties." }, { group: "make", icon: "cube", title: "Shapes that stay editable", text: "Cube, cylinder, sphere, torus, stairs, arch and more, plus starter models like a table, chair or barrel. Change their sizes any time in Properties." },
{ group: "make", icon: "pen", title: "Draw a shape anywhere", text: "Click an outline on the ground or straight on the face of another object: it becomes a new part, gets added to it, or cuts into it." }, { group: "make", icon: "pen", title: "Draw a shape anywhere", text: "Click an outline on the ground or straight on the face of another object: it becomes a new part, gets added to it, or cuts into it." },
{ group: "make", icon: "combine", title: "Add, subtract, overlap", text: "Combine objects: add them together, take one out of another, or keep only where they overlap. The result is always closed and ready to print." }, { group: "make", icon: "combine", title: "Add, subtract, overlap", text: "Combine objects: add them together, take one out of another, or keep only where they overlap. Exact, and always closed, so always ready to print." },
{ group: "make", icon: "points", title: "Real shape editing", text: "Points, edges and faces. Extrude, inset, round edges, loop cut, knife, bridge, push and pull. Soft selection as in Blender and Maya: near points follow (Shift+O)." }, { group: "make", icon: "hole", title: "Cuts you can still move", text: "Cut one object out of another and keep the cutter: move it, turn it, change its shape, and the hole follows. It goes with what it cuts. Apply when you're done." },
{ group: "make", icon: "ruler", title: "Exact sizes", text: "Type a number while you drag for exactly that: extrude, inset, round edges, move, turn, scale, a drawn line's length. Dimensions in Properties, snapping to points and the middles of edges and faces, measuring." },
{ group: "make", icon: "text", title: "Text, spin, import", text: "3D text from any font. An outline spun round an axis into a vase or a wheel, or up into a screw thread. STL, OBJ, 3MF and glTF brought in, the right way up." },
{ group: "make", icon: "points", title: "Real shape editing", text: "Points, edges and faces. Extrude, inset, round edges, loop cut, knife, bridge, push and pull, edge slide, creases that stay sharp when smoothed, both sides at once. Soft selection as in Blender and Maya: near points follow (Shift+O)." },
{ group: "make", icon: "hole", title: "Holes for screws and nuts", text: "Round, rectangle, triangle or hexagon. M2 to M8 screw and nut sizes ready, with a little room added so the print actually fits." }, { group: "make", icon: "hole", title: "Holes for screws and nuts", text: "Round, rectangle, triangle or hexagon. M2 to M8 screw and nut sizes ready, with a little room added so the print actually fits." },
{ group: "make", icon: "copies", title: "Copies and thickness", text: "Copies in a row or round in a circle. Make a surface thick, or a solid hollow with walls exactly as thick as you need." }, { group: "make", icon: "copies", title: "Copies and thickness", text: "Copies in a row, round in a circle, or along a path, turning as it turns. Make a surface thick, or a solid hollow with walls exactly as thick as you need." },
{ group: "paint", icon: "sculpt", title: "Sculpt it like clay", text: "Raise, puff out, smooth, flatten, pinch and grab the surface with a brush, the same on both sides if you like. A shape with too few points is made finer first, keeping its shape." }, { group: "paint", icon: "sculpt", title: "Sculpt it like clay", text: "Raise, puff out, smooth, flatten, pinch and grab the surface with a brush, the same on both sides if you like. A shape with too few points is made finer first, keeping its shape." },
{ group: "print", icon: "sphere", title: "Materials you can see", text: "Gold, chrome, brushed steel, wood, ceramic, rubber and more, or set how metal and rough it is yourself; save a look as your own material for every file. Shown in the view, and exported with it." }, { group: "print", icon: "sphere", title: "Materials you can see", text: "Gold, chrome, brushed steel, wood, ceramic, rubber and more, or set how metal and rough it is yourself; save a look as your own material for every file. Shown in the view, and exported with it." },
{ group: "paint", icon: "brush", title: "Paint and stickers", text: "Paint on the model or on its flat picture. Paste any picture (Ctrl+V) and it goes on like a sticker that bends over edges and corners." }, { group: "paint", icon: "brush", title: "Paint and stickers", text: "Paint on the model or on its flat picture, on both sides at once, or only inside a stencil. Paste any picture (Ctrl+V) and it goes on like a sticker that bends over edges and corners." },
{ group: "paint", icon: "layout", title: "Layout tab", text: "Move, turn and size the flat frames of the surface by hand. The paint follows, so the model looks the same." }, { group: "paint", icon: "layout", title: "Layout tab", text: "Move, turn and size the flat frames of the surface by hand. The paint follows, so the model looks the same." },
{ group: "print", icon: "print", title: "Made for 3D printing", text: "Your printer's plate in the view, sizes in millimetres, checks for holes and flipped faces with fix buttons, overhangs shown red, weight and filament." }, { group: "print", icon: "print", title: "Made for 3D printing", text: "Your printer's plate in the view, sizes in millimetres and a scaler (percent, inches to mm, fit the plate), checks with one repair button, overhangs in red, walls too thin in yellow, a layer-by-layer slice preview, weight and filament." },
{ group: "print", icon: "sun", title: "See it rendered", text: "Solid view for modelling, a real renderer with sky, sun and soft shadows when you want to see it properly. Save a picture with F12." }, { group: "print", icon: "sun", title: "See it rendered", text: "Solid view for modelling, a real renderer with sky, sun and soft shadows when you want to see it properly. Save a picture with F12." },
{ group: "work", icon: "search", title: "Find anything", text: "F3 or Ctrl+Space finds any command by name. Hold Space for the tools round the mouse, Shift+Space for the views. Your own keys for any command, the undo history, and workspaces: the panels as you had them." },
{ group: "work", icon: "folder", title: "Folders and groups", text: "Layers with folders inside folders, drag and drop, show/hide and lock whole groups, and a button on every row that brings the camera to it." }, { group: "work", icon: "folder", title: "Folders and groups", text: "Layers with folders inside folders, drag and drop, show/hide and lock whole groups, and a button on every row that brings the camera to it." },
{ group: "work", icon: "phone", title: "On your phone too", text: "Not a viewer: the whole modeller. Big buttons, one finger turns the view, two move and pinch to zoom, holding still is a right-click. Files through the phone's own picker." }, { group: "work", icon: "phone", title: "On your phone too", text: "Not a viewer: the whole modeller. Big buttons, one finger turns the view, two move and pinch to zoom, holding still is a right-click. Files through the phone's own picker." },
{ group: "work", icon: "code", title: "Scripts, if you want them", text: "Lua in a Script panel: build a town in a loop, turn a profile into a vase, move points by a formula. Kept in the .fry with the model; F5 runs one, Ctrl+Z takes it all back." }, { group: "work", icon: "code", title: "Scripts, if you want them", text: "Lua in a Script panel: build a town in a loop, turn a profile into a vase, move points by a formula. Kept in the .fry with the model; F5 runs one, Ctrl+Z takes it all back." },
{ group: "work", icon: "plug", title: "Plug-ins", text: "A script in the plug-ins folder stays loaded: it adds commands to the Add, Object or Script menu (with a little form for their settings) and materials to the picker. Stairs, scatter and more materials come with it." }, { group: "work", icon: "plug", title: "Plug-ins", text: "A script in the plug-ins folder stays loaded: it adds commands to the Add, Object or Script menu (with a little form for their settings) and materials to the picker. Or a mouse tool in the Toolbox. Stairs, scatter, stamp and more materials come with it." },
{ group: "work", icon: "save", title: "Never lose work", text: "Its own packed .fry file, autosave in the background, recovery after a crash, and a Save / Don't save / Cancel when closing." }, { group: "work", icon: "save", title: "Never lose work", text: "Its own packed .fry file, autosave in the background, recovery after a crash, and a Save / Don't save / Cancel when closing." },
], ],
@ -124,6 +128,7 @@ fry.frame()`,
}, },
versions: [ versions: [
{ v: "0.8", date: "2026-10-21", items: ["Quicker to use, exact to size", "Find any command by name (F3), the tools round the mouse (Space), your own keys, the undo history, workspaces", "Typed sizes while dragging, snapping, measuring, a line's length while drawing", "Cuts you can still move; combining that's exact", "3D text, spin and screw, copies along a path, crease, edge slide, mirror editing", "Import STL, OBJ, 3MF and glTF", "Print: a scaler, thin walls, a slice preview, repair all at once", "Painting both sides and inside a stencil; plug-ins can add mouse tools", "Far away things no longer vanish; steadier and smoother on phones, which stay sideways"] },
{ v: "0.7", date: "2026-10-21", items: ["Steadier and tidier", "Cutting a shape inside an earlier cut no longer crashes, and cuts come out closed", "Edges hidden behind the surface stay hidden on big or cut-up shapes", "Every panel has a least size, so it stays readable; the first layout fits small windows", "Eye and padlock buttons in Layers; the tabs fit narrow windows", "A failed tool keeps your redo"] }, { v: "0.7", date: "2026-10-21", items: ["Steadier and tidier", "Cutting a shape inside an earlier cut no longer crashes, and cuts come out closed", "Edges hidden behind the surface stay hidden on big or cut-up shapes", "Every panel has a least size, so it stays readable; the first layout fits small windows", "Eye and padlock buttons in Layers; the tabs fit narrow windows", "A failed tool keeps your redo"] },
{ v: "0.6", date: "2026-10-20", items: ["Sculpting, scripts and a Mac app", "Sculpting: raise, puff out, smooth, flatten, pinch and grab", "Materials shown in the view, sixteen to start from", "Scripts: Lua and a Script panel, with examples, kept in the .fry", "Plug-ins: menu commands and materials, three to start with", "Your own materials", "Soft selection, bridge, push / pull, smooth points, show only the selected", "macOS: one app for Apple silicon and Intel", "A new look (Niveus): light and dark, following the desktop", "A new logo", "Drop a file on the window to open it"] }, { v: "0.6", date: "2026-10-20", items: ["Sculpting, scripts and a Mac app", "Sculpting: raise, puff out, smooth, flatten, pinch and grab", "Materials shown in the view, sixteen to start from", "Scripts: Lua and a Script panel, with examples, kept in the .fry", "Plug-ins: menu commands and materials, three to start with", "Your own materials", "Soft selection, bridge, push / pull, smooth points, show only the selected", "macOS: one app for Apple silicon and Intel", "A new look (Niveus): light and dark, following the desktop", "A new logo", "Drop a file on the window to open it"] },
{ v: "0.5", date: "2026-10-19", items: ["Builds for Windows, Linux (AppImage) and Android", "A phone layout: big buttons, finger gestures, the phone's file picker", "Apache License 2.0"] }, { v: "0.5", date: "2026-10-19", items: ["Builds for Windows, Linux (AppImage) and Android", "A phone layout: big buttons, finger gestures, the phone's file picker", "Apache License 2.0"] },

View file

@ -25,6 +25,9 @@
phone: '<rect x="7" y="2.5" width="10" height="19" rx="2.5"/><path d="M11 18.5h2"/>', phone: '<rect x="7" y="2.5" width="10" height="19" rx="2.5"/><path d="M11 18.5h2"/>',
save: '<path d="M4 12a8 8 0 1 0 2.4-5.7"/><path d="M4 4v4h4M12 8v4l3 2"/>', save: '<path d="M4 12a8 8 0 1 0 2.4-5.7"/><path d="M4 4v4h4M12 8v4l3 2"/>',
code: '<path d="m8 7-5 5 5 5M16 7l5 5-5 5M13.5 4l-3 16"/>', code: '<path d="m8 7-5 5 5 5M16 7l5 5-5 5M13.5 4l-3 16"/>',
search: '<circle cx="10.5" cy="10.5" r="6"/><path d="m15 15 5.5 5.5"/>',
ruler: '<rect x="2.5" y="8" width="19" height="8" rx="1"/><path d="M6.5 8v3M10.5 8v4M14.5 8v3M18.5 8v4"/>',
text: '<path d="M5 6.5V4.5h14v2M12 4.5v15M9 19.5h6"/>',
sculpt: '<path d="M4 18c3-1 4-6 8-6s5 5 8 6"/><circle cx="12" cy="7" r="3"/>', sculpt: '<path d="M4 18c3-1 4-6 8-6s5 5 8 6"/><circle cx="12" cy="7" r="3"/>',
plug: '<path d="M9 3v5M15 3v5M6.5 8h11v3a5.5 5.5 0 0 1-11 0zM12 16.5V21"/>', plug: '<path d="M9 3v5M15 3v5M6.5 8h11v3a5.5 5.5 0 0 1-11 0zM12 16.5V21"/>',
sphere: '<circle cx="12" cy="12" r="8.5"/><path d="M3.5 12c2.5 2 14.5 2 17 0"/><circle cx="9" cy="8.5" r="1.5" fill="currentColor" stroke="none"/>', sphere: '<circle cx="12" cy="12" r="8.5"/><path d="M3.5 12c2.5 2 14.5 2 17 0"/><circle cx="9" cy="8.5" r="1.5" fill="currentColor" stroke="none"/>',

View file

@ -1240,7 +1240,7 @@ private:
// ───────────────────────────── commands ───────────────────────────── // ───────────────────────────── commands ─────────────────────────────
// Everything that can be done, by name: for the command search, keys of your own, the pies. // Everything that can be done, by name: for the command search, keys of your own, the pies.
void buildCommands(); void openSearch(); void runCommand(const std::string& id); void commandSearch(); void buildCommands(); void openSearch(); void runCommand(const std::string& id); void commandItem(const char* id); void commandSearch();
// The pies: the tools (Space), or the views (Shift+Space), round the mouse while it's held. // The pies: the tools (Space), or the views (Shift+Space), round the mouse while it's held.
void pieFrame(ImGuiIO& io); void pieFrame(ImGuiIO& io);
// Keys of your own: kept in keys.txt (a line each: the command's id, a tab, the key). // Keys of your own: kept in keys.txt (a line each: the command's id, a tab, the key).

View file

@ -551,6 +551,17 @@ auto App::runCommand(const std::string& id) -> void {
} }
} }
// A menu item for a command: its name, its key (your own if you gave it one), greyed when it can't be done now.
auto App::commandItem(const char* id) -> void {
for (const fry::Command& c : commands_)
if (c.id == id) {
const auto mine = myKeys_.find(c.id);
const std::string keys = mine != myKeys_.end() ? fry::chordName(mine->second) : c.keys;
if (ImGui::MenuItem(c.name.c_str(), keys.empty() ? nullptr : keys.c_str(), false, c.usable())) runCommand(c.id);
return;
}
}
auto App::commandSearch() -> void { auto App::commandSearch() -> void {
if (!search_.open) return; if (!search_.open) return;
if (const int i = search_.draw(commands_, recentCommands_); i >= 0) runCommand(commands_[size_t(i)].id); if (const int i = search_.draw(commands_, recentCommands_); i >= 0) runCommand(commands_[size_t(i)].id);
@ -623,6 +634,7 @@ auto App::menus() -> void {
if (ImGui::BeginMenu("Edit")) { if (ImGui::BeginMenu("Edit")) {
if (ImGui::MenuItem("Undo", "Ctrl+Z", false, !undo_.empty())) undo(); if (ImGui::MenuItem("Undo", "Ctrl+Z", false, !undo_.empty())) undo();
if (ImGui::MenuItem("Redo", "Ctrl+Y", false, !redo_.empty())) redo(); if (ImGui::MenuItem("Redo", "Ctrl+Y", false, !redo_.empty())) redo();
commandItem("edit.history");
ImGui::Separator(); ImGui::Separator();
if (ImGui::MenuItem("Duplicate", "Ctrl+D", false, mode_ == Mode::Object)) duplicateSelected(); if (ImGui::MenuItem("Duplicate", "Ctrl+D", false, mode_ == Mode::Object)) duplicateSelected();
if (ImGui::MenuItem("Join into one", "Ctrl+J", false, mode_ == Mode::Object && selected_.size() > 1)) joinSelected(); if (ImGui::MenuItem("Join into one", "Ctrl+J", false, mode_ == Mode::Object && selected_.size() > 1)) joinSelected();
@ -640,6 +652,9 @@ auto App::menus() -> void {
if (ImGui::MenuItem("More (grow)", "Ctrl +")) growSelection(); if (ImGui::MenuItem("More (grow)", "Ctrl +")) growSelection();
if (ImGui::MenuItem("Less (shrink)", "Ctrl -")) shrinkSelection(); if (ImGui::MenuItem("Less (shrink)", "Ctrl -")) shrinkSelection();
if (ImGui::MenuItem("Everything joined to it", "L")) selectLinked(); if (ImGui::MenuItem("Everything joined to it", "L")) selectLinked();
commandItem("select.similar");
commandItem("select.loop");
commandItem("select.ring");
ImGui::MenuItem("A loop: Alt+click or double-click", nullptr, false, false); ImGui::MenuItem("A loop: Alt+click or double-click", nullptr, false, false);
ImGui::EndDisabled(); ImGui::EndDisabled();
ImGui::Separator(); ImGui::Separator();
@ -669,6 +684,7 @@ auto App::menus() -> void {
if (ImGui::MenuItem("Join (just as they are)", "Ctrl+J", false, many)) joinSelected(); if (ImGui::MenuItem("Join (just as they are)", "Ctrl+J", false, many)) joinSelected();
ImGui::Separator(); ImGui::Separator();
if (ImGui::MenuItem("Make it thick (or hollow)...", nullptr, false, any)) showThicken_ = true; if (ImGui::MenuItem("Make it thick (or hollow)...", nullptr, false, any)) showThicken_ = true;
commandItem("object.spin");
if (ImGui::MenuItem("Join flat faces side by side", nullptr, false, any)) cleanFlatFaces(); if (ImGui::MenuItem("Join flat faces side by side", nullptr, false, any)) cleanFlatFaces();
pluginMenuItems("object"); pluginMenuItems("object");
ImGui::EndMenu(); ImGui::EndMenu();
@ -692,6 +708,11 @@ auto App::menus() -> void {
if (ImGui::MenuItem("Push out / pull in...", "Alt+S")) startPush(); if (ImGui::MenuItem("Push out / pull in...", "Alt+S")) startPush();
if (ImGui::MenuItem("Bridge two faces")) bridgeNow(); if (ImGui::MenuItem("Bridge two faces")) bridgeNow();
ImGui::MenuItem("Soft selection", "Shift+O", &softSel_); ImGui::MenuItem("Soft selection", "Shift+O", &softSel_);
ImGui::EndDisabled();
commandItem("shape.crease");
commandItem("shape.slide");
commandItem("shape.mirror");
ImGui::BeginDisabled(!ed);
if (ImGui::MenuItem("Make into its own object", "P")) separateSelected(); if (ImGui::MenuItem("Make into its own object", "P")) separateSelected();
if (ImGui::MenuItem("Delete", "Del")) deleteElements(); if (ImGui::MenuItem("Delete", "Del")) deleteElements();
ImGui::EndDisabled(); ImGui::EndDisabled();
@ -722,6 +743,9 @@ auto App::menus() -> void {
if (ImGui::MenuItem("Frame selected", "F")) frameSelected(); if (ImGui::MenuItem("Frame selected", "F")) frameSelected();
if (ImGui::MenuItem("Frame everything", "Home")) frameAll(); if (ImGui::MenuItem("Frame everything", "Home")) frameAll();
if (ImGui::MenuItem("Show only the selected (again: all)", "/", false, !selected_.empty())) showOnly(selected_); if (ImGui::MenuItem("Show only the selected (again: all)", "/", false, !selected_.empty())) showOnly(selected_);
ImGui::Separator();
commandItem("tools.measure");
commandItem("view.workspace");
ImGui::EndMenu(); ImGui::EndMenu();
} }
if (ImGui::BeginMenu("Script")) { if (ImGui::BeginMenu("Script")) {
@ -755,6 +779,7 @@ auto App::menus() -> void {
} }
if (ImGui::BeginMenu("Help")) { if (ImGui::BeginMenu("Help")) {
if (ImGui::MenuItem("Keys and mouse", "F1")) showHelp_ = true; if (ImGui::MenuItem("Keys and mouse", "F1")) showHelp_ = true;
commandItem("help.search");
if (ImGui::MenuItem("About Fry3DX")) showAbout_ = true; if (ImGui::MenuItem("About Fry3DX")) showAbout_ = true;
ImGui::EndMenu(); ImGui::EndMenu();
} }
@ -813,6 +838,7 @@ auto App::addMenuItems() -> void {
setTool(Tool::Draw); setTool(Tool::Draw);
} }
if (ImGui::MenuItem("Reference picture...")) dialog(4); if (ImGui::MenuItem("Reference picture...")) dialog(4);
commandItem("add.text");
} }
// How the last item's key looks: filled when it's the one in use, sunk while held. // How the last item's key looks: filled when it's the one in use, sunk while held.
@ -917,7 +943,7 @@ auto App::toolbox() -> void {
for (const fry::PluginTool& t : plugins_[i].p->tools) { for (const fry::PluginTool& t : plugins_[i].p->tools) {
if (std::exchange(first, false)) ImGui::SeparatorText("Plug-in tools"); if (std::exchange(first, false)) ImGui::SeparatorText("Plug-in tools");
const bool on = pluginTool_ == std::pair(plugins_[i].file, t.name); const bool on = pluginTool_ == std::pair(plugins_[i].file, t.name);
if (ImGui::Selectable(std::format("{}##{}", t.name, plugins_[i].file).c_str(), on, 0, ImVec2(w, 0))) if (ImGui::Selectable(std::format("{}##{}", t.name, plugins_[i].file).c_str(), on, 0, ImVec2(w, touch() ? 34.0f : 0.0f)))
on ? setTool(Tool::Select) : void((pluginTool_ = {plugins_[i].file, t.name}, tool_ = Tool::Select, say(t.name + ": click in the view (Esc stops)"))); on ? setTool(Tool::Select) : void((pluginTool_ = {plugins_[i].file, t.name}, tool_ = Tool::Select, say(t.name + ": click in the view (Esc stops)")));
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s%s(%s)", t.help.c_str(), t.help.empty() ? "" : "\n", plugins_[i].p->name.c_str()); if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s%s(%s)", t.help.c_str(), t.help.empty() ? "" : "\n", plugins_[i].p->name.c_str());
} }