+static int max(int a, int b) { return a > b ? a : b; }
+
+
+void GuiPainter::button(int x, int y, int w, int h, bool mouseHover)
+{
+ if (mouseHover)
+ fillRectangle(x, y, w, h, Color_buttonhoverbg);
+ else
+ fillRectangle(x, y, w, h, Color_buttonbg);
+ buttonFrame(x, y, w, h);
+}
+
+
+void GuiPainter::buttonFrame(int x, int y, int w, int h)
+{
+ line(x, y, x, y + h - 1, Color_buttonframe);
+ line(x - 1 + w, y, x - 1 + w, y + h - 1, Color_buttonframe);
+ line(x, y - 1, x - 1 + w, y - 1, Color_buttonframe);
+ line(x, y + h - 1, x - 1 + w, y + h - 1, Color_buttonframe);
+}
+
+
+void GuiPainter::rectText(int x, int y, docstring const & str,
+ FontInfo const & font, Color back, Color frame)
+{
+ int width;
+ int ascent;
+ int descent;
+
+ FontMetrics const & fm = theFontMetrics(font);
+ fm.rectText(str, width, ascent, descent);
+
+ if (back != Color_none)
+ fillRectangle(x + 1, y - ascent + 1, width - 1,
+ ascent + descent - 1, back);
+
+ if (frame != Color_none)
+ rectangle(x, y - ascent, width, ascent + descent, frame);
+
+ text(x + 3, y, str, font);
+}
+
+
+void GuiPainter::buttonText(int x, int y, docstring const & str,
+ FontInfo const & font, bool mouseHover)
+{
+ int width;
+ int ascent;
+ int descent;
+
+ FontMetrics const & fm = theFontMetrics(font);
+ fm.buttonText(str, width, ascent, descent);
+
+ static int const d = Inset::TEXT_TO_INSET_OFFSET / 2;
+
+ button(x + d, y - ascent, width - d, descent + ascent, mouseHover);
+ text(x + Inset::TEXT_TO_INSET_OFFSET, y, str, font);
+}
+
+
+int GuiPainter::preeditText(int x, int y, char_type c,
+ FontInfo const & font, preedit_style style)
+{
+ FontInfo temp_font = font;
+ FontMetrics const & fm = theFontMetrics(font);
+ int ascent = fm.maxAscent();
+ int descent = fm.maxDescent();
+ int height = ascent + descent;
+ int width = fm.width(c);
+
+ switch (style) {
+ case preedit_default:
+ // default unselecting mode.
+ fillRectangle(x, y - height + 1, width, height, Color_background);
+ dashedUnderline(font, x, y - descent + 1, width);
+ break;
+ case preedit_selecting:
+ // We are in selecting mode: white text on black background.
+ fillRectangle(x, y - height + 1, width, height, Color_black);
+ temp_font.setColor(Color_white);
+ break;
+ case preedit_cursor:
+ // The character comes with a cursor.
+ fillRectangle(x, y - height + 1, width, height, Color_background);
+ underline(font, x, y - descent + 1, width);
+ break;
+ }
+ text(x, y - descent + 1, c, temp_font);
+
+ return width;
+}
+
+
+void GuiPainter::doubleUnderline(FontInfo const & f, int x, int y, int width)
+{
+ FontMetrics const & fm = theFontMetrics(f);
+
+ int const below = max(fm.maxDescent() / 2, 2);
+
+ line(x, y + below, x + width, y + below, f.realColor());
+ line(x, y + below - 2, x + width, y + below - 2, f.realColor());
+}
+
+
+void GuiPainter::underline(FontInfo const & f, int x, int y, int width)
+{
+ FontMetrics const & fm = theFontMetrics(f);
+
+ int const below = max(fm.maxDescent() / 2, 2);
+ int const height = max((fm.maxDescent() / 4) - 1, 1);
+
+ if (height < 2)
+ line(x, y + below, x + width, y + below, f.realColor());
+ else
+ fillRectangle(x, y + below, width, below + height, f.realColor());
+}
+
+
+void GuiPainter::strikeoutLine(FontInfo const & f, int x, int y, int width)
+{
+ FontMetrics const & fm = theFontMetrics(f);
+
+ int const middle = max((fm.maxHeight() / 4), 1);
+ int const height = middle/3;
+
+ if (height < 2)
+ line(x, y - middle, x + width, y - middle, f.realColor());
+ else
+ fillRectangle(x, y - middle, width, height, f.realColor());
+}
+
+
+void GuiPainter::dashedUnderline(FontInfo const & f, int x, int y, int width)
+{
+ FontMetrics const & fm = theFontMetrics(f);
+
+ int const below = max(fm.maxDescent() / 2, 2);
+ int height = max((fm.maxDescent() / 4) - 1, 1);
+
+ if (height >= 2)
+ height += below;
+
+ for (int n = 0; n != height; ++n)
+ line(x, y + below + n, x + width, y + below + n, f.realColor(), line_onoffdash);
+}
+
+
+void GuiPainter::wavyHorizontalLine(int x, int y, int width, ColorCode col)
+{
+ setQPainterPen(computeColor(col));
+ int const step = 4;
+ int const xend = x + width;
+ int height = 1;
+ //FIXME: I am not sure if Antialiasing gives the best effect.
+ //setRenderHint(Antialiasing, true);
+ while (x < xend) {
+ height = - height;
+ drawLine(x, y - height, x + step, y + height);
+ x += step;
+ drawLine(x, y + height, x + 2, y + height);
+ x += 2;
+ }
+ //setRenderHint(Antialiasing, false);
+}
+