diff --git a/assets/style.css b/assets/style.css index 9fd0e15..b97cfd2 100644 --- a/assets/style.css +++ b/assets/style.css @@ -326,7 +326,6 @@ img.intro-screenshot { .body-container .olist, .body-container .ulist, .body-container .exampleblock, -.body-container .imageblock, .body-container .listingblock, .body-container .literalblock, .body-container .sidebarblock, @@ -339,6 +338,11 @@ img.intro-screenshot { margin-bottom: 1rem; } +.body-container .imageblock { + /* was 1rem, but it looks ugly to have that space after images */ + margin-bottom: 0rem; +} + .body-container .dlist .dlist, .body-container .dlist .olist, .body-container .dlist .ulist, @@ -658,6 +662,10 @@ img.intro-screenshot { vertical-align: middle; } +.body-container .highlight pre { + padding: 0.5rem; +} + /* Open Collective logo from https://css.gg/open-collective (license: MIT) */ .gg-open-collective, diff --git a/content/blog/2025-09-12_preview_of_next_gen_ui/3d-view.gif b/content/blog/2025-09-12_preview_of_next_gen_ui/3d-view.gif new file mode 100644 index 0000000..73dd9ee Binary files /dev/null and b/content/blog/2025-09-12_preview_of_next_gen_ui/3d-view.gif differ diff --git a/content/blog/2025-09-12_preview_of_next_gen_ui/drag-n-drop.gif b/content/blog/2025-09-12_preview_of_next_gen_ui/drag-n-drop.gif new file mode 100644 index 0000000..77e1b14 Binary files /dev/null and b/content/blog/2025-09-12_preview_of_next_gen_ui/drag-n-drop.gif differ diff --git a/content/blog/2025-09-12_preview_of_next_gen_ui/index.adoc b/content/blog/2025-09-12_preview_of_next_gen_ui/index.adoc new file mode 100644 index 0000000..f086f81 --- /dev/null +++ b/content/blog/2025-09-12_preview_of_next_gen_ui/index.adoc @@ -0,0 +1,311 @@ +--- +date: 2025-09-12 +title: Preview of LibrePCB 2.0's Next-Gen UI +author: U. Bruhin +preview: new-window.png +--- + +I've made a lot of progress with the completely new user interface for +LibrePCB 2.0 and am very excited to share some insights how it will look, +and how it makes LibrePCB better in many ways. + +The Original Problem +-------------------- + +First, let's quickly look back how everything began. Since the early days of +LibrePCB around 2013, we are using Qt as the UI toolkit and the concept was +to implement every editor as a separate window (schematic editor, board editor, +library editor etc.): + +[.imageblock] +{{< imglink "old windows" "old-windows.png" >}} + +But with more features added over time, the UI got more and more cluttered. +Also the paradigm of separate windows is often cumbersome to work with -- e.g. +having just one library and one project opened required to constantly switch +between four(!) windows. Even a dual-monitor setup was not enough to work +efficiently with LibrePCB. So it was clear we need a completely new +organization of windows and editors. Generally we could have done that with Qt, +but its traditional approach makes is really hard to pursue more modern +UI paradigms, not to mention the effort and the error-proneness it involves. +In the past I have struggled many times with Qt to create nice UI elements, +thus I didn't feel confident to build up a completely new UI with Qt again. + +Slint: A Declarative UI Language +-------------------------------- + +In the blog post +link:{{< relref "blog/2024-10-17_roadmap_2.0/index.adoc" >}}[NGI0 Grant for LibrePCB 2.0] +I listed a few possible solutions how to build a more modern user interface. The +most promising option was https://slint.dev/[Slint], a relatively new UI +toolkit (open-source & written in Rust) which uses a custom, declarative +language to describe the UI. With the declarative approach, relations and +behavior can be easily specified right in the UI description: + +{{< highlight qml >}} +Window { + Button { + x: parent.width - self.width - 5px; // place 5px from the right border + y: 5px; // place 5px from the top border + text: @tr("Open Project"); + } +} +{{< /highlight >}} + +It may sound trivial to place a button at the top right corner of its parent, +but with the procedural approach of Qt this is often not trivially doable. In +many cases, it requires to implement event handlers in C++ which update the +widgets position whenever the parent object's size or the widgets's own size +has changed. Writing such code is time-consuming and error-prone, while the +declarative approach of Slint is quick, easy and safe -- not just for +this trivial example, but also in more complex cases. For a large project like +LibrePCB, which consists of hundrets of UI elements, the declarative approach +is really a game-changer for us developers! _(Side note: As of today, LibrePCB +contains 23.746 lines of Slint code!)_ + +An Incremental Migration +------------------------ + +Unfortunately, even with several months of full-time work, LibrePCB is too +large to be migrated to Slint by 100% at once -- to avoid delaying the next +release too much, we need to do the migration in steps. All the main windows & +editors first, and the remaining dialogs and wizards in later releases. Also +our whole business logic depends on Qt (it is much more than just a UI +framework), thus our dependency on Qt will remain for a long time. + +So the question is, can we mix Qt with Slint? In the end, LibrePCB only works +if the main thread is running Qt's event loop. But Slint only works when the +main thread is running _their_ event loop. So at first glance it seems we +have a very bad conflict here :-/ + +In fact, Slint supports +https://docs.slint.dev/latest/docs/slint/guide/backends-and-renderers/backends_and_renderers/[different backends] +for interaction with the underlying system, e.g. for input events handling +and window drawing. These are (interestingly) Qt, +https://docs.rs/winit/latest/winit/[winit] and LinuxKMS. Winit comes with the +ability of GPU-accelerated rendering, which would be interesting for +performance reasons. But unfortunately right now we can't use winit because +of the event loop conflict. + +Luckily Slint's Qt backend avoids that problem since Slint will run Qt's +event loop for us. So the event loop will process the events for both, the +Slint UI and the LibrePCB backend. This works because Slint and LibrePCB +are compiled and linked against the same Qt library. It also allows us to +mix the new Slint window with legacy Qt dialogs & wizards, so we can do +a step-by-step migration. + +One Window For Everything +------------------------- + +Enough background information for now, let's have a look at the new UI of +LibrePCB 2.0. The most important thing is that all the individual windows +mentioned above have been replaced by a single, multifunctional window. +Within that window, any kind of "document" (e.g. a footprint, a schematic or +a board) is opened as a tab. The toolbars of the new window now depend on +which tab is currently active, because for example the footprint editor +supports other features than the schematic editor. This is how the new window +currently looks like: + +[.imageblock.rounded-window.window-border] +{{< imglink "new window" "new-window.png" >}} + +By the way, in this new window you can even have multiple projects (and +libraries) opened at the same time! All the opened projects and libraries are +listed in the documents panel, and the contained entities can be opened as +individual tabs. + +Sidebar & Panel +~~~~~~~~~~~~~~~ + +A lot of functionality is accessible through the new sidebar. Depending on +context, there are different kinds of panels available. For example if you're +working on a schematic, there is a panel which displays ERC messages. But if +you're working on a board, that panel will display DRC messages. + +[.imageblock] +{{< imglink "side panels" "side-panels.png" >}} + +The sidebar also shows you status information about various parts of the +application. For example you see if there are ERC warnings or outdated +workspace libraries without even opening the corresponding panel: + +[.imageblock] +{{< imglink "side buttons" "side-buttons.png" >}} + +Working Area +~~~~~~~~~~~~ + +The most important part of our UI is of course the working area where you +draw schematics or layout traces etc. This area has been improved in many ways. +Not only that _everything_ is now a tab (remember that schematics were not +tabs in the old UI), you can now even split the window into multiple sections +and open tabs side-by-side. For example if you're working on a single-monitor +setup, it is now easy to work on the board while still having the schematics +in sight: + +[.imageblock.rounded-window.window-border] +{{< imglink "split section" "split-section.png" >}} + +Tabs and sections can be easily arranged by drag&drop -- *see it in action +in link:/blog/2025-09-12_preview_of_next_gen_ui/drag-n-drop.gif[this video]*. + +In addition, the working area has been maximized and decluttered to have as +much of the screen size available for the graphics view as possible. For +example, tool buttons are now overlays inside the editors rather than +traditional toolbars spanning the whole window height or width even if +only a third of them is filled with buttons. There is no such wasted space +anymore in the new UI. + +Statusbar & Notifications +~~~~~~~~~~~~~~~~~~~~~~~~~ + +We already had a status bar in the old UI, but it was purely visual and not +interactive. Instead of just _displaying_ the grid interval, the new UI +allows you to _modify_ the grid interval and the grid style right in the status +bar -- no dedicated dialog window is required anymore. Also the state of +placement locks is displayed and can be toggled right in the status bar. +Last but not least, there is a completely new notification system which +displays messages and ongoing operations in an expandable/collapsible popup +in the bottom right corner: + +[.imageblock] +{{< imglink "statusbar" "statusbar.png" >}} + +Multi-Monitor Ready +~~~~~~~~~~~~~~~~~~~ + +If you are working on a multi-monitor setup and now worry that a single window +is worse than the multiple windows we had before -- of course this use-case +is covered as well. Although the new window replaces all the old windows, +I have implemented the ability to open _multiple instances_ of that window +at the same time. So you decide whether to display schematic and board +side-by-side by splitting a single window, or by opening schematic and +board in entirely separate windows -- everything is possible with the new +concept! + +Simplified Library Management +----------------------------- + +The old library manager was not that bad, but it was more complicated than +necessary due to its "operation-based" workflow of manually triggering the +installation or uninstallation of libraries, with those operations even +spread across multiple list views and pages. + +The new library manager is much simpler (but as functional as before) +by following a "state-based" paradigm now. Instead of triggering the +installation or uninstallation of individual libraries, you now just check +the libraries you like to use (or uncheck those you don't want anymore) and +a single _apply_ operation performs all the necessary installations or +removals at once. Beside the improved user experience, this also fixes some +issues of the old concept (e.g. limitations of the automatic dependency +management). + +[.imageblock.rounded-window.window-border] +{{< imglink "library manager" "library-manager.gif" >}} + +Configurable 3D View +-------------------- + +The old 3D view was just a pure read-only display with no configuration +options at all. But for a detailed review of the design, sometimes it is +necessary to hide specific things -- e.g. the devices or the solder paste. +This is now possible by changing the transparency of those objects: + +[.imageblock.rounded-window.window-border] +{{< imglink "3d view" "3d-view.gif" >}} + + +Built-In Hints, Tips & Guides +----------------------------- + +In my vision, an EDA tool should support engineers/makers as well as +possible (in a non-disruptive way) to help them creating PCB designs without +errors as quick as possible. The new UI has therefore various new tips & hints +implemented which show up in certain situations. Many of them are especially +useful for LibrePCB beginners to ensure a smooth first-use experience, but +some are useful for everyone to minimize errors or wasted time. + +As an example, the built-in PCB ordering feature now displays the state of +the electrical- & design-rule checks as a friendly reminder to review & fix +any issues before ordering a (possibly faulty) PCB. The order panel contains +direct hyperlinks to the ERC & DRC panels, and even allows to run the DRC +right from the order panel. And as an additional psychological effect, the +order button is only highlighted if there are no issues, though it is always +clickable. 🤓 + +[.imageblock.rounded-window.window-border] +{{< imglink "order pcb" "order-pcb.gif" >}} + +What's Next? +------------ + +Even though the new UI is the biggest change in the history of LibrePCB, +this is just the beginning of a new user experience. There is still a lot +of room for improvements which we will take care of after the LibrePCB 2.0 +release. Just a few examples: + +* Object property editors (incl. multi-object editing) in side panel to get + rid of modal dialogs +* Replace remaining modal dialogs & wizards by integrating them as tabs + or lightweight popups +* Reflect typical workflows by the UI, for higher productivity and intuitivity +* Productivity improvements, e.g. drag&drop, more keyboard shortcuts, + hints, links to docs, ... +* Theme improvements / cleanup / polishing, maybe some day support + customizable themes + +All the completed tasks and the planned tasks, together with more details +and previews of the new UI, are summarized in +https://github.com/LibrePCB/LibrePCB/issues/1494[this issue]. Of course there +are also a lot of new non-UI features beeing developed for LibrePCB 2.0 and +beyond, those are tracked in separate issues. This blog post just focused on +the UI things due to its huge relevance in this moment. + +Give it a Try! +~~~~~~~~~~~~~~ + +If you like to try out the new UI already, we have nightly builds available +*https://download.librepcb.org/nightly_builds/new-ui-with-file-format-1_0/[here]*. +In contrast to the current `master` branch, these builds still use the stable +file format 1.0 so no changes will be made to your library- and project files. +But of course there might still be some bugs -- if you experience any issues +or annoyances, or have any other feedback, please +link:{{< relref "help/help/index.adoc" >}}[let us know]! + +++++ +
+ + + Get Nightly Builds + + }}" > + + Give Feedback + + }}" > + + Support My Work + +
+++++ + +Btw, if you are curious about the timeline of the LibrePCB 2.0 release: +There are still some new features to be implemented (mostly non-UI things now) +and it is hard to say when they are finished. But roughly I'd estimate it +should be ready in around 2-3 months. If you like to support my work on +the LibrePCB project, any link:{{< relref "donate/index.adoc" >}}[donations] +are highly appreciated and help me to keep the development ongoing. icon:heart[] + +--- + +Credits +------- + +[.right.ms-3] +{{< imglink "NGI0" "nlnet-ngi0.png" "https://nlnet.nl/project/LibrePCB2.0/" 130 >}} + +A majority of these updates were part of the +link:{{< relref "blog/2024-10-17_roadmap_2.0/index.adoc" >}}[NGI0 Commons grant] +we receive from link:https://nlnet.nl[NLnet], thanks a lot for their support! +Also a special thanks to the Slint developers who helped me with support, +feature development and bugfixes during this migration. diff --git a/content/blog/2025-09-12_preview_of_next_gen_ui/library-manager.gif b/content/blog/2025-09-12_preview_of_next_gen_ui/library-manager.gif new file mode 100644 index 0000000..d9f58e4 Binary files /dev/null and b/content/blog/2025-09-12_preview_of_next_gen_ui/library-manager.gif differ diff --git a/content/blog/2025-09-12_preview_of_next_gen_ui/new-window.png b/content/blog/2025-09-12_preview_of_next_gen_ui/new-window.png new file mode 100644 index 0000000..77c1c61 Binary files /dev/null and b/content/blog/2025-09-12_preview_of_next_gen_ui/new-window.png differ diff --git a/content/blog/2025-09-12_preview_of_next_gen_ui/nlnet-ngi0.png b/content/blog/2025-09-12_preview_of_next_gen_ui/nlnet-ngi0.png new file mode 100644 index 0000000..c64ddbf Binary files /dev/null and b/content/blog/2025-09-12_preview_of_next_gen_ui/nlnet-ngi0.png differ diff --git a/content/blog/2025-09-12_preview_of_next_gen_ui/old-windows.png b/content/blog/2025-09-12_preview_of_next_gen_ui/old-windows.png new file mode 100644 index 0000000..e77544b Binary files /dev/null and b/content/blog/2025-09-12_preview_of_next_gen_ui/old-windows.png differ diff --git a/content/blog/2025-09-12_preview_of_next_gen_ui/order-pcb.gif b/content/blog/2025-09-12_preview_of_next_gen_ui/order-pcb.gif new file mode 100644 index 0000000..8f30216 Binary files /dev/null and b/content/blog/2025-09-12_preview_of_next_gen_ui/order-pcb.gif differ diff --git a/content/blog/2025-09-12_preview_of_next_gen_ui/side-buttons.png b/content/blog/2025-09-12_preview_of_next_gen_ui/side-buttons.png new file mode 100644 index 0000000..b252e4f Binary files /dev/null and b/content/blog/2025-09-12_preview_of_next_gen_ui/side-buttons.png differ diff --git a/content/blog/2025-09-12_preview_of_next_gen_ui/side-panels.png b/content/blog/2025-09-12_preview_of_next_gen_ui/side-panels.png new file mode 100644 index 0000000..4523fa3 Binary files /dev/null and b/content/blog/2025-09-12_preview_of_next_gen_ui/side-panels.png differ diff --git a/content/blog/2025-09-12_preview_of_next_gen_ui/split-section.png b/content/blog/2025-09-12_preview_of_next_gen_ui/split-section.png new file mode 100644 index 0000000..8d86195 Binary files /dev/null and b/content/blog/2025-09-12_preview_of_next_gen_ui/split-section.png differ diff --git a/content/blog/2025-09-12_preview_of_next_gen_ui/statusbar.png b/content/blog/2025-09-12_preview_of_next_gen_ui/statusbar.png new file mode 100644 index 0000000..e841c83 Binary files /dev/null and b/content/blog/2025-09-12_preview_of_next_gen_ui/statusbar.png differ