#!/usr/bin/env qore

# This is basically a direct port of the QT widget example
# "charactermap" to Qore using Qore's "qt" module.

# Note that Qore's "qt" module requires QT 4.3 or above

# use the "qt-gui" module
%requires qt-gui

# this is an object-oriented program, the application class is "charactermap_example"
%exec-class charactermap_example
# require all variables to be explicitly  declared
%require-our
# enable all parse warnings
%enable-all-warnings

class CharacterWidget inherits QWidget
{
    constructor($parent) : QWidget($parent)
    {
	$.createSignal("characterSelected(const QString &)");
	$.displayFont = new QFont();

	$.squareSize = 24;
	$.columns = 32;
	$.lastKey = -1;
	$.setMouseTracking(True);
    }

    updateFont($font)
    {
	$.displayFont.setFamily($font.family());
	$.squareSize = max(24, (new QFontMetrics($.displayFont)).xHeight() * 3);
	$.adjustSize();
	$.update();
    }

    updateSize($fontSize)
    {
	$.displayFont.setPointSize($fontSize);
	$.squareSize = max(24, (new QFontMetrics($.displayFont)).xHeight() * 3);
	$.adjustSize();
	$.update();
    }

    updateStyle($fontStyle)
    {
	my $fontDatabase = new QFontDatabase();
	my $oldStrategy = $.displayFont.styleStrategy();
	$.displayFont = $fontDatabase.font($.displayFont.family(), $fontStyle, $.displayFont.pointSize());
	$.displayFont.setStyleStrategy($oldStrategy);
	$.squareSize = max(24, (new QFontMetrics($.displayFont)).xHeight() * 3);
	$.adjustSize();
	$.update();
    }

    updateFontMerging($enable)
    {
	if ($enable)
	    $.displayFont.setStyleStrategy(QFont::PreferDefault);
	else
	    $.displayFont.setStyleStrategy(QFont::NoFontMerging);
	$.adjustSize();
	$.update();
    }

    sizeHint()
    {
	return new QSize($.columns*$.squareSize, (65536/$.columns)*$.squareSize);
    }

    mouseMoveEvent($event)
    {
	my $widgetPosition = $.mapFromGlobal($event.globalPos());
	my $key = ($widgetPosition.y
		   ()/$.squareSize)*$.columns + $widgetPosition.x()/$.squareSize;

	my $text = sprintf("<p>Character: <span style=\"font-size: 24pt; font-family: %s\">%s</span><p>Value: 0x%x",
			   $.displayFont.family(), $key, $key);
	QToolTip::showText($event.globalPos(), $text, $self);
    }

    mousePressEvent($event)
    {
	if ($event.button() == Qt::LeftButton) {
	    $.lastKey = ($event.y
			 ()/$.squareSize)*$.columns + $event.x()/$.squareSize;
	    my $lkc = new QChar($.lastKey);
	    if ($lkc.category() != QChar::NoCategory)
		$.emit("characterSelected(QString)", $lkc);
	    $.update();
	}
	else
	    QWidget::$.mousePressEvent($event);
    }

    paintEvent($event)
    {
	my $painter = new QPainter($self);
	$painter.fillRect($event.rect(), new QBrush(Qt::white));
	$painter.setFont($.displayFont);

	my $redrawRect = $event.rect();
	my $beginRow = $redrawRect.top()/$.squareSize;
	my $endRow = $redrawRect.bottom()/$.squareSize;
	my $beginColumn = $redrawRect.left()/$.squareSize;
	my $endColumn = $redrawRect.right()/$.squareSize;

	$painter.setPen(new QPen(Qt::gray));
	for (my $row = $beginRow; $row <= $endRow; ++$row) {
	    for (my $column = $beginColumn; $column <= $endColumn; ++$column) {
		$painter.drawRect($column*$.squareSize, $row*$.squareSize, $.squareSize, $.squareSize);
	    }
	}

	my $fontMetrics = new QFontMetrics($.displayFont);
	$painter.setPen(new QPen(Qt::black));
	for (my $row = $beginRow; $row <= $endRow; ++$row) {

	    for (my $column = $beginColumn; $column <= $endColumn; ++$column) {

		my $key = $row*$.columns + $column;
		$painter.setClipRect($column*$.squareSize, $row*$.squareSize, $.squareSize, $.squareSize);

		if ($key == $.lastKey)
		    $painter.fillRect($column*$.squareSize + 1, $row*$.squareSize + 1, $.squareSize, $.squareSize, new QBrush(Qt::red));

		$painter.drawText($column*$.squareSize + ($.squareSize / 2) - $fontMetrics.width(new QChar($key))/2,
				  $row*$.squareSize + 4 + $fontMetrics.ascent(),
				  new QChar($key));
	    }
	}
    }
}

class MainWindow inherits QMainWindow
{
    constructor()
    {
	my $centralWidget = new QWidget();

	my $fontLabel = new QLabel(TR("Font:"));
	$.fontCombo = new QFontComboBox();
	my $sizeLabel = new QLabel(TR("Size:"));
	$.sizeCombo = new QComboBox();
	my $styleLabel = new QLabel(TR("Style:"));
	$.styleCombo = new QComboBox();
	my $fontMergingLabel = new QLabel(TR("Automatic Font Merging:"));
	$.fontMerging = new QCheckBox();
	$.fontMerging.setChecked(True);

	$.scrollArea = new QScrollArea();
	$.characterWidget = new CharacterWidget();
	$.scrollArea.setWidget($.characterWidget);

	$.findStyles($.fontCombo.currentFont());
	$.findSizes($.fontCombo.currentFont());

	$.lineEdit = new QLineEdit();
	my $clipboardButton = new QPushButton(TR("&To clipboard"));

	$.clipboard = QApplication::clipboard();

	$.connect($.fontCombo, SIGNAL("currentFontChanged(const QFont &)"), SLOT("findStyles(const QFont &)"));
	$.connect($.fontCombo, SIGNAL("currentFontChanged(const QFont &)"), SLOT("findSizes(const QFont &)"));
	$.characterWidget.connect($.fontCombo, SIGNAL("currentFontChanged(const QFont &)"), SLOT("updateFont(const QFont &)"));
	$.characterWidget.connect($.sizeCombo, SIGNAL("currentIndexChanged(const QString &)"), SLOT("updateSize(const QString &)"));
	$.characterWidget.connect($.styleCombo, SIGNAL("currentIndexChanged(const QString &)"), SLOT("updateStyle(const QString &)"));
	$.connect($.characterWidget, SIGNAL("characterSelected(const QString &)"), SLOT("insertCharacter(const QString &)"));
	$.connect($clipboardButton, SIGNAL("clicked()"), SLOT("updateClipboard()"));
	$.characterWidget.connect($.fontMerging, SIGNAL("toggled(bool)"), SLOT("updateFontMerging(bool)"));

	my $controlsLayout = new QHBoxLayout();
	$controlsLayout.addWidget($fontLabel);
	$controlsLayout.addWidget($.fontCombo, 1);
	$controlsLayout.addWidget($sizeLabel);
	$controlsLayout.addWidget($.sizeCombo, 1);
	$controlsLayout.addWidget($styleLabel);
	$controlsLayout.addWidget($.styleCombo, 1);
	$controlsLayout.addWidget($fontMergingLabel);
	$controlsLayout.addWidget($.fontMerging, 1);
	$controlsLayout.addStretch(1);

	my $lineLayout = new QHBoxLayout();
	$lineLayout.addWidget($.lineEdit, 1);
	$lineLayout.addSpacing(12);
	$lineLayout.addWidget($clipboardButton);

	my $centralLayout = new QVBoxLayout();
	$centralLayout.addLayout($controlsLayout);
	$centralLayout.addWidget($.scrollArea, 1);
	$centralLayout.addSpacing(4);
	$centralLayout.addLayout($lineLayout);
	$centralWidget.setLayout($centralLayout);

	$.setCentralWidget($centralWidget);
	$.setWindowTitle(TR("Character Map"));
    }

    findStyles($font)
    {
	my $fontDatabase = new QFontDatabase();

	my $currentItem = $.styleCombo.currentText();
	$.styleCombo.clear();

	foreach my $style in ($fontDatabase.styles($font.family()))
	    $.styleCombo.addItem($style);

	my $styleIndex = $.styleCombo.findText($currentItem);

	if ($styleIndex == -1)
	    $.styleCombo.setCurrentIndex(0);
	else
	    $.styleCombo.setCurrentIndex($styleIndex);
    }

    findSizes($font)
    {
	my $fontDatabase = new QFontDatabase();

	my $currentSize = $.sizeCombo.currentText();
	$.sizeCombo.blockSignals(True);
	$.sizeCombo.clear();

	my $size;
	if ($fontDatabase.isSmoothlyScalable($font.family(), $fontDatabase.styleString($font))) {
	    foreach $size in (QFontDatabase::standardSizes()) {
		$.sizeCombo.addItem(string($size));
		$.sizeCombo.setEditable(True);
	    }

	} else {
	    foreach $size in ($fontDatabase.smoothSizes($font.family(), $fontDatabase.styleString($font))) {
		$.sizeCombo.addItem(string($size));
		$.sizeCombo.setEditable(False);
	    }
	}

	$.sizeCombo.blockSignals(False);

	my $sizeIndex = $.sizeCombo.findText($currentSize);

	if ($sizeIndex == -1)
	    $.sizeCombo.setCurrentIndex(max(0, $.sizeCombo.count() / 3));
	else
	    $.sizeCombo.setCurrentIndex($sizeIndex);
    }

    insertCharacter($character)
    {
	$.lineEdit.insert($character);
    }

    updateClipboard()
    {
	$.clipboard.setText($.lineEdit.text(), QClipboard::Clipboard);
	$.clipboard.setText($.lineEdit.text(), QClipboard::Selection);
    }

}

class charactermap_example inherits QApplication
{
    constructor()
    {
	my $window = new MainWindow();
	$window.show();
	$.exec();
    }
}