/* Copyright 2006-2026 The QElectroTech Team This file is part of QElectroTech. QElectroTech is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. QElectroTech is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with QElectroTech. If not, see . */ // SPDX-License-Identifier: GPL-2.0-or-later #ifndef GENERICDEVICE_H #define GENERICDEVICE_H #include #include #include #include #include #include #include #include #include /** @brief The GenericDevice namespace A generic device is a plain box symbol with terminals on any side, made by the generic device wizard for a device used too rarely to draw a symbol by hand (a VSD, a power supply). Everything here is pure: a description of the device (Spec) goes in, an ordinary element definition comes out. No widget, no scene, no project. Coordinates are the element's own, with (0, 0) at the top-left corner of the box body. Every terminal, stub and the body size are multiples of the grid step, so a device placed on the grid puts every terminal on a grid point and wires to it run straight. */ namespace GenericDevice { enum Side { Left = 0, Right, Top, Bottom }; constexpr int SideCount = 4; constexpr int Grid = 10; ///< grid step of the folio constexpr int Stub = 10; ///< terminal point is this far outside the body constexpr int MinWidth = 40; constexpr int MinHeight = 30; constexpr int Inset = 3; ///< names sit this far inside the body edge constexpr int MaxPatternCount = 200; ///< largest {n} or {a-b} a pattern may expand /** @brief The Slot struct One position along a side: a terminal, a gap the user asked for, or padding added to line groups up across opposite sides. Gaps and padding take up a pitch of space and hold no terminal; a gap may carry a divider mark, padding never does. */ struct Slot { enum Kind { Terminal, Gap, Padding }; Kind kind = Terminal; QString name; QString function; QString type = QStringLiteral("Generic"); ///< Generic, Inner or Outer QUuid uuid; bool isTerminal() const { return kind == Terminal; } static Slot terminal(const QString &name) { Slot s; s.name = name; return s; } static Slot gap() { Slot s; s.kind = Gap; return s; } static Slot padding() { Slot s; s.kind = Padding; return s; } /// The text drawn beside the terminal: "name function", or the name. QString shownText() const; }; using Slots = QList; /** @brief The Spec struct Everything the wizard collects. sides[] are ordered top to bottom (left, right) and left to right (top, bottom). */ struct Spec { QString name; QString label; QString manufacturer; QString reference; QString description; bool show_reference = true; Slots sides[SideCount]; int pitch = 20; ///< 10 to 50, a multiple of the grid int extra_width = 0; ///< grid squares added to the automatic size int extra_height = 0; bool mark_gaps = true; ///< draw a divider mark on each gap bool line_up = true; ///< pad groups so dividers meet across the box int terminalCount() const; }; /** @brief The Fonts struct What the names and the label are drawn with. Measuring with the font the folio will draw with is what keeps names inside the box. */ struct Fonts { QFont names; QFont label; }; /** @brief The Layout struct Where everything goes, computed from a Spec. Pure geometry. */ struct Layout { struct PlacedTerminal { Slot slot; Side side; QPointF point; ///< the terminal point, outside the body QPointF edge; ///< where its stub meets the body }; struct Name { QPointF pos; ///< baseline-left, as a static text part is anchored QString text; int rotation = 0; }; int body_width = 0; int body_height = 0; int auto_width = 0; ///< the size before the extra width/height int auto_height = 0; Slots sides[SideCount]; ///< the spec's list after line-up padding QList terminals; QList names; QList dividers; QRectF label_box; ///< x, y, width and the height of one line QStringList warnings; }; struct PatternResult { Slots list; QString error; ///< empty when the pattern was read bool ok() const { return error.isEmpty(); } }; struct PasteResult { Slots sides[SideCount]; bool has_side[SideCount] = {false, false, false, false}; int rows = 0; ///< rows read QStringList bad_rows; ///< rows that could not be read, as typed }; QString sideName(Side side); PatternResult expandPattern(const QString &pattern); QString toPattern(const Slots &list, bool *expressible = nullptr); Slots applyPattern(const Slots ¤t, const Slots &expanded); Slots groupEvery(const Slots &list, int n); Slots resize(const Slots &list, int count, int group_every); void lineUpGroups(Slots &a, Slots &b); void numberPins(Spec &spec); bool hasNumberedPins(const Spec &spec); void nameUnnamed(Spec &spec); PasteResult parsePastedTable(const QString &text); Layout layout(const Spec &spec, const Fonts &fonts); QDomElement toDefinition(const Spec &spec, const Fonts &fonts, QDomDocument &document, const QString &version = QString()); bool fromDefinition(const QDomElement &definition, const Fonts &fonts, Spec *spec); } #endif // GENERICDEVICE_H