manual new line in QGraphicsText Item - qt

i created a editable text class inheriting QGraphicsTextitem and with setTextIntraction flag im allowing the user to enter the text in the QGraphicsTextItem.
now i want to add a new line manually when the graphicsTextitem width exceeds the viewport width . but i cant find the relevant way to manually add a new line when the textWidth exceeds the width of the viewport.
i managed to shift the text left and up as
QGraphicsView *view = scene()->views()[0];
QRect viewport_rect(0, 0, view->viewport()->width(), view->viewport()->height());
QRectF visible_scene_rect = view->mapToScene(viewport_rect).boundingRect();
qreal sceneRightEnd = visible_scene_rect.right();
qreal sceneBottom = visible_scene_rect.bottom();
QPointF textItemRight = mapToScene( now.bottomRight() ) ;
if(textItemRight.x() >= sceneRightEnd)
{
this->moveBy(sceneRightEnd - textItemRight.x(), 0);
}
if(textItemRight.y() >= sceneBottom )
{
this->moveBy( 0, ( sceneBottom - textItemRight.y() ));
}

You can set the width of your text item by calling:
QGraphicsTextItem::setTextWidth(qreal width)
The default width is -1 which causes the text not to be broken into multiple lines.
If you set a width and the actual text is wider than the specified width then it will be broken into multiple lines.

Related

How to calculate QTextEdit height accurately by its contents to get rid of vertical scrollbars?

I need a QTextEdit widget which height grows or shrinks to the size of the inner content. I didn't find built-in solution and decided to make my own with connections to &QTextEdit::textChanged signals that will update size of the widget at runtime. In the code snippet I flattened my custom component to raw QTextEdit for simplicity. The problem is that calculation via QFontMetrics is inaccurate, a vertical scrollbar appears with only some pixels to scroll
I want to get rid of any vertical scrollbars in these text widgets.
However, I don't need to get rid of horizontal scrollbars and here is the second problem arises. Seemingly, horizontal scrolls occupy space in the viewport of the text widget and its internal height shrinks by the height of the scrollbar itself
void TestWindow::setupUi(QWidget *parent)
{
QVBoxLayout *v_box0 = new QVBoxLayout(parent);
v_box0->setContentsMargins(0, 0, 0, 0);
QVBoxLayout *v_scroll_layout = new QVBoxLayout();
v_scroll_layout->setContentsMargins(0, 0, 0, 0);
v_scroll_layout->setSpacing(0);
v_scroll_layout->setAlignment(::Qt::AlignTop);
QWidget *scroll_content = new QWidget();
scroll_content->setLayout(v_scroll_layout);
QScrollArea *v_scroll = new QScrollArea();
v_scroll->setWidgetResizable(true);
v_scroll->setWidget(scroll_content);
v_box0->addWidget(v_scroll);
QSize size;
QTextEdit *edit0 = new QTextEdit();
edit0->setLineWrapMode(QTextEdit::NoWrap);
edit0->setText("Hello World 1\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11");
edit0->setFont(viewer_font);
size = edit0->fontMetrics().size(0, edit0->document()->toPlainText());
edit0->document()->setDocumentMargin(0);
edit0->setMinimumHeight(size.height());
QTextEdit *edit1 = new QTextEdit();
edit1->setLineWrapMode(QTextEdit::NoWrap);
edit1->setText("New item");
edit1->setFont(viewer_font);
size = edit1->fontMetrics().size(0, edit1->document()->toPlainText());
edit1->document()->setDocumentMargin(0);
edit1->setMinimumHeight(size.height());
v_scroll_layout->addWidget(edit0);
v_scroll_layout->addWidget(edit1);
setFixedHeight(300);
}

Fit QDialog window to size of text

I have a QDialog class that takes in a QString. I am calling setFixedSize with a set width and height but I want the QDialog to be more dynamic and fit to the size of the text.
I have tried adjustSize() but all that did was shrink the window to the point where the text was cut off.
ConfirmDialog::ConfirmDialog(const QString& message, QWidget* parent)
: QDialog(parent)
{
setFixedSize(WIDTH, HEIGHT);
statusLabel->setText(tr("Confirmation"));
statusDetailsLabel->setText(message);
statusDetailsLabel->setWordWrap(true);
}
I always see a Window with size of dimensions WIDTH and HEIGHT. I want it to fit the test.
One way would be to use Font Metrics to get the bounding rects of each label, and then set the window size to the sum of both rects + some padding to make it look nice.
One problem you will run into is having wordwrap on. How do you determine the width of the window, if you are word wrapping? So I've added a "MAXWIDTH" for the window. If your text is shorter and does not require word wrap - the window will shrink to fit it. If it does require word wrap, it will not go over your set size.
ConfirmDialog::ConfirmDialog(const QString& message, QWidget* parent)
: QDialog(parent)
{
const int MAXWIDTH = 400;
const int VERTICALPADDING = 50;
// Create Layout
QLabel *statusLabel = new QLabel(this);
QLabel *statusDetailsLabel = new QLabel(this);
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(statusLabel);
layout->addWidget(statusDetailsLabel);
setLayout(layout);
// Populate Text
statusLabel->setText(tr("Confirmation"));
statusDetailsLabel->setText(message);
statusDetailsLabel->setWordWrap(false); // Start w/ word wrap off.
// Font metrics to get the sizes of our text.
QFontMetrics fontMetricsLabel(statusLabel->font());
QFontMetrics fontMetricsDetail(statusDetailsLabel->font());
// Get max width - label or detail lable, whichever is longer.
int width = std::max(fontMetricsLabel.boundingRect("Confirmation").width(),
fontMetricsDetail.boundingRect(message).width());
// Check that we do not go over our MAXWIDTH.
if(width > MAXWIDTH) width = MAXWIDTH;
// Enable word wrapping.
statusDetailsLabel->setWordWrap(true);
// Get the heigts of both boxes.
int height = std::max(fontMetricsLabel.boundingRect("Confirmation").height(),
fontMetricsDetail.boundingRect(message).height());
// Set window size.
this->setFixedSize(width, height + VERTICALPADDING);
}

Qt: measure tooltip height, or anchor tooltip from bottom

I have the following code to place a tooltip at text-cursor position in a QLineEdit (i.e. the bottom left corner of the tooltip stays just above the text cursor):
setToolTip(tip);
QPoint cur = mapToGlobal(cursorRect().topLeft());
QHelpEvent *event = new QHelpEvent(QEvent::ToolTip,
QPoint(pos().x(), pos().y()),
QPoint(cur.x(), cur.y() - 2 * height() - 2));
QApplication::postEvent(this, event);
I roughly estimated tooltip height as QLineEdit::height(), but that's wrong, and becomes terribly wrong when the tooltip wraps on multiple lines, because it would cover the line edit.
Is there a way to measure a tooltip text height?
Or a way to place a tooltip by specifying the bottom-left or bottom-center as anchor point?
It seems using QFontMetrics with QToolTip::font() works fine.
Here's my solution:
setToolTip(tip);
QFontMetrics fm(QToolTip::font());
QRect r = fm.boundingRect(QRect(0, 0, 500, 50), 0, tip);
QPoint cur = mapToGlobal(cursorRect().topLeft());
QHelpEvent *event = new QHelpEvent(QEvent::ToolTip,
QPoint(pos().x(), pos().y()),
QPoint(cur.x(), cur.y() - height() - r.height() - 4));
QApplication::postEvent(this, event);

How to align QProgressBar in the center in status bar and show text?

I am showing progress bar in status bar but it not really aligned well. I would like it to show up center aligned if possible or at least have some margin on the left, I am attaching a snapshot.
The 2nd issue I have is I want it to display the text but text is not showing.
_progressBar = new QProgressBar(this);
_progressBar->setRange(0, 0);
_progressBar->setTextVisible(true);
_progressBar->setFormat("Connecting");
ui->statusBar->addPermanentWidget( _progressBar, 2 );
Since we are at it, the stretch parameter (in ctor) has default value of 0 but it doesn't really say what other values it could have. 0 producess the shortest size and any other value great than 0 I tried gives the maximum. there is nothing in the middle. I tried to fix issue with stretchvalue but not succescful.
First issue:
If you want to add some space at the left of the progress bar, you can use a QSpacerItem. Wrap this QSpacerItem and the QProgressBar inside a QWidget, then add this QWidget in the status bar:
QProgressBar * _progressBar = new QProgressBar();
_progressBar->setRange(1, 10);
_progressBar->setValue(2);
_progressBar->setTextVisible(true);
_progressBar->setFormat("Connecting");
QWidget * w = new QWidget;
QHBoxLayout * _hlayout = new QHBoxLayout();
_hlayout->addSpacerItem(new QSpacerItem(40,1));
_hlayout->addWidget(_progressBar);
w->setLayout(_hlayout);
ui->statusBar->addPermanentWidget(w, 2);
.
Second issue:
Your text will be displayed once you call QProgressBar::setValue with a value inside the range you specified:
QProgressBar * _progressBar = new QProgressBar();
_progressBar->setRange(0, 100);
_progressBar->setValue(10);
_progressBar->setTextVisible(true);
_progressBar->setFormat("Connecting");
ui->statusBar->addPermanentWidget( _progressBar, 2 );
By the way, the empty margin at the right of the bar is where the text is displayed.
If you want to get rid of that space, you can add _progressBar->setAlignment(Qt::AlignCenter); to center your text over the QProgressBar:

GtkToolButton with custom icon but of stock icon size

I've a GtkToolBar which has say 3 GtkToolButtons with each of these having a stock icon value, and hence they all appear in the same size; now I added a 4th GtkToolButton with a custom image (.png), which was of an arbitrary dimension and only this button ended up looking huge (since the image was of higher resolution). What do I do to scale this GtkToolButton to match the other 3 buttons?
Here's the code which does what I briefed about:
GtkWidget *custom_icon = gtk_image_new_from_file(path);
GtkToolItem *toolbar_item = gtk_toggle_tool_button_new();
gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(toolbar_item), custom_icon);
gtk_tool_button_set_label(GTK_TOOL_BUTTON(toolbar_item), "Custom Item");
gtk_toolbar_insert(toolbar, toolbar_item, -1);
Here is another solution.
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(icon_file_path, NULL);
int width, height;
gdk_pixbuf_get_file_info (icon_file_path, &width, &height);
gtk_icon_theme_add_builtin_icon ("custom_icon", width, pixbuf);
g_object_unref (G_OBJECT (pixbuf));
GtkToolItem *toolbar_item = gtk_toggle_tool_button_new();
gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON(toolbar_item), "custom_icon");
If you have the image in different sizes, you can add them all and let Gtk choose the one of the correct size (or resize if not found): Just repeat the first five lines for each of the image files.
You can use your icon anywhere else and its size will also be adjusted automatically.
For example, to use it for your main window:
gtk_window_set_icon_name(GTK_WINDOW(main_window), "custom_icon");
Found it out myself! Here's the trick so that it helps someone like me. Query the icon size from the stock menu item, which is a enum (standard values like GTK_ICON_SIZE_BUTTON, GTK_ICON_SIZE_LARGE_TOOLBAR, etc.). Now get the pixel size using gtk_icon_size_lookup. Create a pixbuf from the custom icon/image file with the right dimensions. Create a GtkImage from that and set it to the new menu item and you're done!
GtkToolItem *stock_menu_item = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_NEW);
GtkIconSize toolbar_icon_size = gtk_tool_item_get_icon_size(stock_menu_item);
gint width = 0, height = 0;
gtk_icon_size_lookup(toolbar_icon_size, &width, &height);
GdkPixbuf *app_icon = gdk_pixbuf_new_from_file_at_size(icon_file_path, width, height, NULL);
GtkImage *tray_icon = gtk_image_new_from_pixbuf(app_icon);
g_object_unref(app_icon);
app_icon = NULL;
GtkToolItem *toolbar_item = gtk_toggle_tool_button_new();
gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(toolbar_item), tray_icon);

Resources