Qt QML: in-file definition of reusable objects - qt

I have a Qml component that is reasonably large so that I want to make it a reusable component but it is too small/non-generic such that I want to avoid creating its own .qml file.
It seems like Components are the right method to define reusable objects in the same file, but when I do that I don't know how to access and change properties of the contained objects.
More specifically, imagine having an in-file definition like this
Component {
id: myReusableComponent
// This cannot be set because component does not allow properties
// (Would work fine in a separate file myReusableComponent.qml)
// property alias string innerText: innerText.text
Rectangle {
id: rect
width: 200
height: 200
color: "red"
Text {
id: innerText
text: "Want to set text later"
}
}
How can I reuse this component later, while changing some properties of it?
I know the following is not valid syntax, but I want to use it similarly to this:
Loader {
id: hello
sourceComponent: myReusableComponent
item.innerText: "Hello" }
Text { text: "Some other stuff in between" }
Loader {
id: world
sourceComponent: myReusableComponent
item.anchors.left: hello.right
item.rect.width: 100
item.rect.color: "blue"
item.innerText: "World" }
Loader {
id: excl
sourceComponent: myReusableComponent
item.rect.color: "green"
item.innerText: "!!!" }
etc...
Any ideas? Or is there a fundamentally different way of doing this?
What I essentially want is reusability of QML objects that are defined in place while still being able to change the properties of them.
This seems to be related but does not solve the problem of creating multiple objects. Repeaters seem to be useful but don't give me the flexibility I want.
NOTE: I will add some remarks about the answers here since they might get overlooked in the comments.
I like all three answers from Blabbouze, derM and ddriver!
I accepted Blabbouze's answer because it provides a concrete solution that is closest to what I was looking for.
However, I also didn't know about the overhead of Loaders and might consider using a different approach after reading derM's answer.
Finally, dynamic object creation as suggested by ddriver is not exactly what I was looking for but might be useful for others.
Thanks everyone!

I think you are looking for onLoaded() signal. It is emitted when the Loader have successfully created the Component.
You can then access your loaded type properties with item.
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Component {
id: myReusableComponent
Rectangle {
id: rect
property alias innerText: innerText.text
width: 200
height: 200
color: "red"
Text {
id: innerText
text: "Want to set text later"
}
}
}
Loader {
id: hello
sourceComponent: myReusableComponent
onLoaded: {
item.innerText = "hello"
}
}
Loader {
id: world
sourceComponent: myReusableComponent
anchors.left: hello.right
onLoaded: {
item.width = 100
item.color = "blue"
item.innerText = "World"
}
}
}

At first I will try to explain why you do not want to do it
If the Component is reused - even in one file and not only by the means of Repeaters, ListViews e.t.c - you should consider creating a seperate file, to keep your file clean and readable.
If you create inline-components, and then create the instances by the means of a Loader just to be able to create them, they come with an overhead, that can be tolerated if the component is really enormous, or you really need the Loader for the possibility to change the source dynamically. Otherwise, it helps you only to make everything complex, and raise the ressource consumption.
There is almost no penalty for outlaying the code into multiple files. So do it, when ever you have a reasonable, logically enclosed unit - and especially when you are going to reuse it multiple times in a file.
Use the Component when you are planning to use this as a delegate. Some perfere to directly declare the delegate where it is used. I do so, if there are only few properties to set.
Especially if you have multiple Views that share the same delegate-prototype, it is a good idea to use the Component.
If you really need to use a Loader (for the reasons you need a Loader and not for non-dynamic object creation) then you can use a Component to avoid the need of the onLoaded-event. It enables you to preconfigure the Component, and set the event-handlers without the need of a Connections-Object.
Ok - now a short answer to your question:
You can create instances of a Component by many means:
Loader
Views (ListView, GridView, Repeater ...)
Dynamic Object Creation with JS (componentID.createObject(parent)) at any point where you can execute JS code.
Read: http://doc.qt.io/qt-5/qtqml-javascript-dynamicobjectcreation.html#creating-objects-dynamically

You could also try to use dynamic object creation with components.
So you can have a property Rectangle obj: null, and then:
Component.onCompleted: {
obj = myReusableComponent.createObject(parentItem, {"width" : 100, "color" : "blue" }
}
In addition to Blabbouze's answer, aside from assignments (which are not auto updated as bindings) you can also have bindings if you use the format:
item.prop = Qt.binding(function() { bindingExpressions... })

In Qt5.15 there is a new inline component syntax:
component <component name> : BaseType {
// declare properties and bindings here
}
In the following example, I define NormalText from Text and, subsequently, I define HeadingText from NormalText, then, I use them all in the same QML file:
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Page {
anchors.fill: parent
component NormalText : Text {
Layout.fillWidth: true
font.pointSize: 12
wrapMode: Text.WordWrap
}
component HeadingText : NormalText {
font.pointSize: 14
font.bold: true
}
ColumnLayout {
width: parent.width
HeadingText { text: "Introduction" }
NormalText { text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." }
NormalText { text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." }
}
}
You can Try it Online!
References:
https://www.qt.io/blog/new-qml-language-features-in-qt-5.15

Related

Using ch (character) unit on font-size

My question is very different from this question: Font scaling based on width of container
This previous question and answers do not mention the ch unit.
CSS Tricks shows an example of using the ch unit to size text, https://css-tricks.com/almanac/properties/f/font-size/.
I had assumed that setting font-size to say 75ch would set the font size so that a maximum of 75 characters (or zeros) would fit on a line, within its container. So that when the container width grows or shrinks, the font-size adapts accordingly, so that there is always 75 characters per line.
See The Elements of Typographic Style Applied to the Web http://webtypography.net/2.1.2 "Anything from 45 to 75 characters is widely regarded as a satisfactory length of line"
However it doesn't work like that. I can see the max-width: 75ch limits the width of the text to 75 characters. But that is an entirely different thing.
If the ch unit can't be used on font-size to create responsive font sizes depended on the width of the container, then what is ch based on when used on font-size (as per the CSS Tricks example)?
<div class="text-content">
<p>Nus moluptatur? Quid eum in nosandit, ut voluptae num dit faccumquis qui vollab inctaquam, undis antis et voluptae. Itatenditem qui tem nonecus repedi doluptae pre explautessum is dolupta doluptatum que perunt lant rero te dolestium fugitat emporeiur, ipit est od minim dolesti asitati onsedisci dit magnatecatur se nimini repe est voluptat. Alitatur seruptat. Dercipis nonsequ iandae venim erum que rerionectas ad quate aut undi dis es alit adis dia dio te miligen tinvelis nustis mi, ut militatur atiosam, etur aut eum ut ad qui nonet fugiam facculpa pro molenis et, consenim volorer ercienis endaniste est ut exeria dis voluptam si dolorat. Tationsed maximpellant maximod eiunt undisque imustruntus mintio blant lamet ea volupta tiores ducita qui dolut aut ex ex enitas soluptur? Ebit eium et et exeruntur? At autatisquas siti cone cuptaspedit lamusae sequidi coreperion ea illaut liquaec tusamus, aborepra qui to ellabore vellace atemporemqui ulparchilia nis sit utet is abo. Sa susdaerumquo voluptatibus corro que et laboribus repudipid es is vid maio. Ut doluptate conseniet que volumquia quam excerib erspernamet dolorio. Itaturehenti sum, estiur sinusciliquo bla es enimus autate ex entotas consendio. Ut lit optatibustes vit ute que mo milliciati re, odi dolum re velesto rercitae re elenis exerit omniate et, cuptibusdae quamus.</p>
</div>
.text-content {
max-width: 700px;
}
p {
font-size: 75ch;
}
See JS Fiddle https://jsfiddle.net/n98oq5Lc/
ch as a unit really only makes sense in most cases if you are dealing with a monospaced font - then 75ch max-width really would mean dont let the width go beyond 75 characters. But with non monospaced fonts CSS isn't going to count the characters it's going to use what it deems the width ch to mean (see e.g. https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units If your text is lots of i characters it will have a different number of characters in the element than if it has lots of M.
You can however get a sort of responsive font size by defining it in terms of vw and your element width in terms of vw too. It wont gaurantee how many characters you get in a line (unless you go back to the monospaced idea) though.
I tried CH and it sucks, cause lets say you have word: LISBON ... first 2 characters LI are the same size as S, so based on max-width: 2ch; => LI-S-B-O-N
if you try ch3, then it will be LIS-B-ON
basically doesn't work as intented.
No.
ch is a width but font size is a height.
So 75ch merely adjust the vertical size of the font, not the width in respect to the container.

QDialog with rounded corners have black corners instead of being translucent

I need to create a QDialog with rounded translucent corners. The problem is when doing so, the corners are translucent, but are somehow filled in by the Window's alpha property making it black (which is my understanding of the cause of the problem)
Clearly visible is the rounded edges, but with a black 'background' of sorts. To confirm, this Dialog is a modal dialog launched by a QThread from QMainWindow. It is not the parent window.
The CSS for the QDialog (root) component is:
QDialog {
background-color: rgba(250, 250, 250, 255);
border-radius: 30px;
color: #3C3C3C;
}
with a Component Layout as shown below
I added a drop shadow effect on the QDialog too. This is the constructor code for the QDialog:
UpdateDialog::UpdateDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::UpdateDialog)
{
ui->setupUi(this);
setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
QGraphicsDropShadowEffect* effect = new QGraphicsDropShadowEffect();
effect->setBlurRadius(5);
this->setGraphicsEffect(effect);
}
Notably, the parent QMainWindow has the following attributes set in its constructor
ui->setupUi(this);
statusBar()->hide();
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground, true);
// Set rounded corners style
setStyleSheet("QMainWindow {\n background-color:rgba(240,240,240,255);\n border-radius: 30px;\n}\n\nQDialog {\n border-radius: 30px;\n}");
// Add shadow to main window
QGraphicsDropShadowEffect* effect = new QGraphicsDropShadowEffect(ui->mainWindow);
effect->setBlurRadius(5);
effect->setOffset(4, 4);
this->setGraphicsEffect(effect);
How do I make this QDialog to have rounded translucent corners?
UPDATE: Here is a much better version. The pixelated corners were bugging me, among other things. This one looks smooth as silk and can be styled with either CSS or C++. It does require subclassing the QWidget to be rounded (unlike the first version), but it's worth it. Again I'm using a QMessageBox as the base widget here for simplicity (no layouts/etc), but it would work with any QWidget (may need a Qt::Dialog window flag added).
The message box implementation:
#include <QtWidgets>
class RoundedMessageBox : public QMessageBox
{
Q_OBJECT
public:
explicit RoundedMessageBox(QWidget *parent = nullptr) :
QMessageBox(parent)
{
// The FramelessWindowHint flag and WA_TranslucentBackground attribute are vital.
setWindowFlags(windowFlags() | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint);
setAttribute(Qt::WA_TranslucentBackground);
}
qreal radius = 0.0; // desired radius in absolute pixels
qreal borderWidth = -1.0; // -1 : use style hint frame width; 0 : no border; > 0 : use this width.
protected:
void paintEvent(QPaintEvent *) override
{
if (!(windowFlags() & Qt::FramelessWindowHint) && !testAttribute(Qt::WA_TranslucentBackground))
return; // nothing to do
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
// Have style sheet?
if (testAttribute(Qt::WA_StyleSheetTarget)) {
// Let QStylesheetStyle have its way with us.
QStyleOption opt;
opt.initFrom(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
p.end();
return;
}
// Paint thyself.
QRectF rect(QPointF(0, 0), size());
// Check for a border size.
qreal penWidth = borderWidth;
if (penWidth < 0.0) {
QStyleOption opt;
opt.initFrom(this);
penWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, this);
}
// Got pen?
if (penWidth > 0.0) {
p.setPen(QPen(palette().brush(foregroundRole()), penWidth));
// Ensure border fits inside the available space.
const qreal dlta = penWidth * 0.5;
rect.adjust(dlta, dlta, -dlta, -dlta);
}
else {
// QPainter comes with a default 1px pen when initialized on a QWidget.
p.setPen(Qt::NoPen);
}
// Set the brush from palette role.
p.setBrush(palette().brush(backgroundRole()));
// Got radius? Otherwise draw a quicker rect.
if (radius > 0.0)
p.drawRoundedRect(rect, radius, radius, Qt::AbsoluteSize);
else
p.drawRect(rect);
// C'est finí
p.end();
}
};
Example usage showing both CSS and C++ styling options:
int main(int argc, char *argv[])
{
//QApplication::setStyle("Fusion");
QApplication app(argc, argv);
// Dialog setup
RoundedMessageBox *msgBox = new RoundedMessageBox();
msgBox->setAttribute(Qt::WA_DeleteOnClose);
msgBox->setMinimumSize(300, 300);
msgBox->setWindowTitle("Frameless window test");
msgBox->setText("<h3>Frameless rounded message box.</h3>");
msgBox->setInformativeText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean fermentum erat rhoncus, "
"scelerisque eros ac, hendrerit metus. Nunc ac lorem id tortor porttitor mollis. Nunc "
"tristique orci vel risus convallis, non hendrerit sapien condimentum. Phasellus lorem tortor, "
"mollis luctus efficitur id, consequat eget nulla. Nam ac magna quis elit tristique hendrerit id "
"at erat. Integer id tortor elementum, dictum urna sed, tincidunt metus. Proin ultrices tempus "
"lacinia. Integer sit amet fringilla nunc.");
if (1) {
// Use QSS style
app.setStyleSheet(QStringLiteral(
"QDialog { "
"border-radius: 12px; "
"border: 3.5px solid; "
"border-color: qlineargradient(x1: 1, y1: 1, x2: 0, y2: 0, stop: 0 #ffeb7f, stop: 1 #d09d1e); "
"background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #ffeb7f, stop: 1 #d09d1e); "
"color: #003200; "
"}"
));
}
else {
// Use "native" styling
msgBox->radius = 12.0;
msgBox->borderWidth = 3.5;
QLinearGradient bgGrad(0, 0, 1, 1);
bgGrad.setCoordinateMode(QGradient::ObjectMode);
bgGrad.setColorAt(0.0, QColor("gold").lighter());
bgGrad.setColorAt(1.0, QColor("goldenrod").darker(105));
QLinearGradient fgGrad(bgGrad);
fgGrad.setStart(bgGrad.finalStop());
fgGrad.setFinalStop(bgGrad.start());
QPalette pal;
pal.setBrush(QPalette::Window, QBrush(bgGrad));
pal.setBrush(QPalette::Mid, QBrush(fgGrad));
pal.setBrush(QPalette::WindowText, QColor("darkgreen").darker());
msgBox->setPalette(pal);
msgBox->setForegroundRole(QPalette::Mid); // default is WindowText
msgBox->setBackgroundRole(QPalette::Window); // this is actually the default already
}
// Drop shadow doesn't work.
// QGraphicsDropShadowEffect* effect = new QGraphicsDropShadowEffect();
// effect->setBlurRadius(2);
// msgBox->setGraphicsEffect(effect);
msgBox->show();
return app.exec();
}
ORIGINAL: using a generic QMessageBox and setting a mask on it.
Turned out I could use a simple frameless dialog for an "about" message box in a new app... so here you go. This is the simplest method I can think of w/out re-implementing the widget painting process altogether (like in the Qt clock example). But there's clearly limits to this implementation, and I haven't tried it on a Mac yet.
Also, the drop shadow came in very handy... although you can't actually see it, it does a great job smoothing out the corners. Great idea, even if that wasn't the original intention. :)
#include <QtWidgets>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// Dialog setup. Actually use a QMessageBox for a shorter example.
QMessageBox *msgBox = new QMessageBox();
msgBox->setAttribute(Qt::WA_DeleteOnClose);
msgBox->setMinimumSize(300, 300);
msgBox->setWindowTitle("Frameless window test"); // might still be visible eg. in a taskbar
msgBox->setText("<h3>Frameless rounded message box.</h3>");
msgBox->setInformativeText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean fermentum erat rhoncus, "
"scelerisque eros ac, hendrerit metus. Nunc ac lorem id tortor porttitor mollis. Nunc "
"tristique orci vel risus convallis, non hendrerit sapien condimentum. Phasellus lorem tortor, "
"mollis luctus efficitur id, consequat eget nulla. Nam ac magna quis elit tristique hendrerit id "
"at erat. Integer id tortor elementum, dictum urna sed, tincidunt metus. Proin ultrices tempus "
"lacinia. Integer sit amet fringilla nunc.");
// Here come the styling bits... First need the frameless window flag hint
msgBox->setWindowFlags(msgBox->windowFlags() | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint);
// The desired border radius;
const int radius = 12;
// Style the box with CSS. Set the border radius here.
// The border style helps blend the corners, but could be omitted.
// The background is optional... could add other styling here too.
msgBox->setStyleSheet(QString(
"QDialog { "
"border-radius: %1px; "
"border: 2px solid palette(shadow); "
"background-color: palette(base); "
"}"
).arg(radius));
// The effect will not be actually visible outside the rounded window,
// but it does help get rid of the pixelated rounded corners.
QGraphicsDropShadowEffect* effect = new QGraphicsDropShadowEffect();
// The color should match the border color set in CSS.
effect->setColor(QApplication::palette().color(QPalette::Shadow));
effect->setBlurRadius(5);
msgBox->setGraphicsEffect(effect);
// Need to show the box before we can get its proper dimensions.
msgBox->show();
// Here we draw the mask to cover the "cut off" corners, otherwise they show through.
// The mask is sized based on the current window geometry. If the window were resizable (somehow)
// then the mask would need to be set in resizeEvent().
const QRect rect(QPoint(0,0), msgBox->geometry().size());
QBitmap b(rect.size());
b.fill(QColor(Qt::color0));
QPainter painter(&b);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(Qt::color1);
// this radius should match the CSS radius
painter.drawRoundedRect(rect, radius, radius, Qt::AbsoluteSize);
painter.end();
msgBox->setMask(b);
return app.exec();
}

Dynamic adjustment of size of element in splitlayout to browser window

I built a website using splitLayout that lays out elements horizontally, dividing the available horizontal space into multiple parts. I used 'cellWidths = c("1000px", "200px")', so I got an element with width 1000px and a second element with width 200px.
However, what I actually want is that the second element should fit exactly between the right margin of the first element and the right margin of the browser window, so that when the size and/or shape of the browser window is changed, the width of the second element is adjusted accordingly. I tried: 'cellWidths = c("1000px", "calc(100vw-1000px)")', but unfortunately 'calc' cannot be used here.
I thought about using CSS, including something like 'style = "width: "calc(100vw-1000px)"' within the second element, but until now, I did not have any success by trying that.
The complete code is as follows:
library(shiny)
ui <- tagList(
splitLayout(
cellWidths = c("1000px", "200px"),
cellArgs = list(style = "padding: 6px; white-space: normal;"),
fluidPage(
style = "border: 1px solid silver; height: 627px;"
),
fluidPage(
style = "border: 1px solid silver; height: 627px",
p("Lorem ipsum dolor sit amet, ut alterum facilis disputationi vis, summo percipitur sed ea. Stet senserit persequeris at duo, vis atqui vituperata ex, et has omittam expetenda persequeris. Id usu causae meliore, dolorem lucilius perpetua id vim. Vim at homero timeam viderer, dicunt concludaturque ea eum. Tempor ceteros facilisi ei pro, ea tantas adipisci scribentur vix.")
)
)
)
server <- function(input, output, session) {}
shinyApp(ui = ui, server = server)
Any suggestions?
Unfortunately, I'm not an R programmer, and while I can can take guesses at what 'splitLayout' and 'fluidPage' accomplish for you, I don't know enough to tell you definitively what the fix is.
However, what you're describing can be achieved via CSS by using flexbox. In case you're unfamiliar with it, here's some good information:
https://medium.freecodecamp.org/an-animated-guide-to-flexbox-d280cf6afc35
https://css-tricks.com/snippets/css/a-guide-to-flexbox/

It is possible for my Text to display more text underneath when clicked?

In my application I am creating a help page and I want to create text that when the text is clicked on it displays more description text underneath and when it the title/question is clicked again it hides the text. This is commonly found on many FAQ pages but I am struggling to find a way to do this on JavaFX.
You could use TitledPanes:
Map<String, String> questions = new HashMap();
questions.put("Question 1", "Lorem ipsum dolor sit amet, consectetur"
+ "adipiscing elit, sed do eiusmod tempor incididunt ut labore"
+ "et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud"
+ " exercitation ullamco laboris nisi ut aliquip ex ea commodo"
+ " consequat. Duis aute irure dolor in reprehenderit in voluptate"
+ " velit esse cillum dolore eu fugiat nulla pariatur. Excepteur"
+ " sint occaecat cupidatat non proident, sunt in culpa qui"
+ " officia deserunt mollit anim id est laborum.");
questions.put("Question 2", "Not answered yet");
VBox content = new VBox();
questions.forEach((key, value) -> {
Label label = new Label(value);
TitledPane tp = new TitledPane(key, label);
tp.setExpanded(false);
label.setWrapText(true);
content.getChildren().add(tp);
});
You may want to change the style of the title using a CSS stylesheet though by adding the following stylesheet to the scene:
.titled-pane > .title {
-fx-background-color: transparent transparent transparent;
}
You could always implement it yourself by extending behavior of Text class but javafx has Accordion which combined with TitledPane gives functionality that you are looking for.
Example code of how it can be used:
#Override
public void start(Stage primaryStage) {
TitledPane tp1 = new TitledPane("Text 1", new Text("Your text goes here....."));
TitledPane tp2 = new TitledPane("Text 2", new Text("Another text goes here....."));
TitledPane tp3 = new TitledPane("Text 3", new Text("And yet another text goes here....."));
Accordion accordion = new Accordion();
accordion.getPanes().addAll(tp1, tp2, tp3);
Scene scene = new Scene(accordion, 300, 250);
primaryStage.setTitle("AccordionExample");
primaryStage.setScene(scene);
primaryStage.show();
}

R plot - how to add notes and description to the plot?

I have a long description for my plot. And I also need to put some other information under the plot as well.
But I can't figure it out how I can do it. This is what I have so far,
plot(1:10)
title(
main = "Foo",
sub = 'Description \n Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. ',
font.sub = 1,
font.main = 1
)
result is not good as the description is too long and it has been cut off, also the word description is overlapping with the xlable,
How can I box the description under the plot?
This is what I am after,
an additional info - time period.
wrap the description in a grey box.
adjust the text to the left.
Are these possible?
Just a little lesson about typography: the sub argument of your function allows you to put a sub-title. To he honest such elements are not used very often. What you are trying to achieve is to put a caption (which is a very different elements). Typographic conventions say that captions are placed below the plots for graphs and images and above tables. If you use a preparation system like LaTeX or a word processors I advise you to do not put a caption "inside" the plot (say, as a part of the plot itself) by using R functions but to just put your plain plot without captions in your document and then put captions by using tools available for your editors (word etc. or LaTeX or Knitr or even Powerpoint etc. ).
Anyway, my little and boring lesson about typography does not solve your problem. Here I provide a solution with the layout function of base R and the textplot function of the gplots package but as always I bet there is a more efficient and elegant way to achieve the same goal.
library(gplots)
tex <- "Description Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \nAenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque \npenatibus et magnis dis parturient montes, ascetur ridiculus mus."
layout(matrix(c(2,1)), 0.5, 2)
par(mar=c(1,1,1,1))
textplot(tex, halign = "center")
par(mar=c(1,1,1,1))
plot(1:10)
title(main = "Foo", font.main = 1)
just to go back to boring stuff: this way of doing is very tricky and inefficient from my point of view so I advise you to use other tools as I've said previously.
Last but not least, I think that the right syntax for line breaks is \nword to break and not \n word to break
Here is how the result look:
It can be done by using "mtext", and no space between "\n" and following words, eg. "\nLorem".
text<- "Description \nLorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. \nAenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus \nmus. "
par(mar = c(8, 4, 3, 3))
plot(1:10, main = "Foo")
mtext(text, side = 1, line = 6, cex = 0.8, adj = 0)
## line is margin line, starting at 0 counting outwards; adj=0, left or bottom align, 1, right or top align

Resources