# -*- coding: utf-8 -*-
# cython: profile=False

#  Copyright © 2017  B. Clausius <barcc@gmx.de>
#
#  This program 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 3 of the License, or
#  (at your option) any later version.
#
#  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.

# pylint: disable=C0326,W0614
# although this file is compiled with Python3 syntax, Cython needs at least division from __future__
from __future__ import print_function, division

# This line makes cython happy
global __name__, __package__    # pylint: disable=W0604
#px/__compiled = True
__compiled = False

#pxd/from qt cimport *
from .debug_purepython import *

#pxh>#include <QtCore/QString>
#pxh>QString gettext_translate(const char *text, const char *disambiguation);
#pxh>#include "../../data/ui/qt/main.h"
#pxh>#include "../../data/ui/qt/preferences.h"
#pxh>#include "../../data/ui/qt/help.h"
#pxh>#include "../../data/ui/qt/about.h"
#pxh>#include <QtCore/QPropertyAnimation>
#pxh>#include <QtGui/QDesktopServices>
#pxh>#include <QtGui/QKeyEvent>
#pxh>#include <QtGui/QStandardItemModel>
#pxh>#include <QtGui/QIconEngine>
#pxh>#include <QtGui/QPainter>
#pxh>#include <QtWidgets/QStyledItemDelegate>
#pxh>#include <QtWidgets/QWidget>
#pxh>#include <QtWidgets/QOpenGLWidget>
#pxh>#include <QtWidgets/QLineEdit>
#pxh>#include <QtWidgets/QColorDialog>
#pxh>#include <QtWidgets/QScrollBar>
#pxh>#include <QtWidgets/QListWidget>
#pxh>#include <QtWidgets/QListWidgetItem>
#pxh>#include <QtWidgets/QMenu>
#pxh>
#pxc>#include "[[_qtui_VARIANT]]_moc.h"
#pxc>#include "qtui_p.h"
#pxc>

#px/from libc.stdio cimport printf
def printf(fmt, *args): print(fmt % args, end='')
#px/from libc.stdio cimport puts
puts = print

#px/cdef enum: #
if True:
    DEBUG_MSGEXT = 0x1
    DEBUG_DRAW = 0x2
    DEBUG_FPS = 0x4
#px+cdef long debug
debug = 0
    
def set_debug_flags(module):
    global debug
    if module.DEBUG_MSGEXT: debug |= DEBUG_MSGEXT
    if module.DEBUG_DRAW: debug |= DEBUG_DRAW
    if module.DEBUG_FPS: debug |= DEBUG_FPS
    
#pxm-FUNC PD
def init_module():
    if debug & DEBUG_MSGEXT:
        print('init module:', __name__)
        print('  from package:', __package__)
        print('  compiled:', __compiled)
        
#px+cdef extern from "[[_qtui_VARIANT]]_moc.h":#
#pxm>INDENT

#px+cdef QString gettext_translate(const char *text, const char *disambiguation) with gil


#pxm-QC_CPPCLASS class ShortcutEditor (QLabel):
class ShortcutEditor (QLabel):
    #pxh>QString *key;
    #pxh>
    #pxm-FUNC CH
    def __init__(parent:'QWidget *'):  _("Press a key …")
    #pxc>    : QLabel(gettext_translate("Press a key …", Q_NULLPTR), parent)
        #pxc>{
        #pxc>    setFocusPolicy(Qt::StrongFocus);
        #pxc>    setAutoFillBackground(true);
        #pxc>}
        #pxc>
    #pxh>Q_SIGNAL void key_pressed();
        #pxh>
    #pxm-FUNC CH
    def keyPressEvent(event:'QKeyEvent *'):  pass
        #pxc>{
        #pxc>    switch (event->key()) {
        #pxc>        case Qt::Key_Shift: case Qt::Key_Control: case Qt::Key_Meta:
        #pxc>        case Qt::Key_Alt: case Qt::Key_AltGr:
        #pxc>        case Qt::Key_CapsLock: case Qt::Key_NumLock: case Qt::Key_ScrollLock:
        #pxc>            QLabel::keyPressEvent(event);
        #pxc>            return;
        #pxc>    }
        #pxc>    if (event->count() != 1) {
        #pxc>        QLabel::keyPressEvent(event);
        #pxc>        return;
        #pxc>    }
        #pxc>    int mod = event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier);
        #pxc>    QStringList keylist = QKeySequence(event->key() | int(mod)).toString().split('+');
        #pxc>    if ((event->modifiers() & Qt::KeypadModifier) && !keylist.contains(QStringLiteral("Num")))
        #pxc>        keylist.insert(keylist.size()-1, "Num");
        #pxc>    key = new QString(keylist.join('+'));
        #pxc>    key_pressed();
        #pxc>}
#pxm>CPPCLASS_END

#pxm-QC_CPPCLASS class ShortcutDelegate (QStyledItemDelegate):
class ShortcutDelegate (QStyledItemDelegate):
    #pxh>ShortcutDelegate(QObject *parent) : QStyledItemDelegate(parent) {}
    #pxh>
    #pxm-FUNC CH const
    def createEditor(parent:'QWidget *', option:'const QStyleOptionViewItem &', index:'const QModelIndex &')->'QWidget *':  pass
        #pxc>{
        #pxc>    ShortcutEditor *editor = new ShortcutEditor(parent);
        #pxc>    connect(editor, SIGNAL(key_pressed()), this, SLOT(on_editor_key_pressed()));
        #pxc>    return editor;
        #pxc>}
        #pxc>
    #pxh>void setEditorData(QWidget *editor, const QModelIndex &index) const {}
        #pxc>
    #pxm-FUNC CH const
    def setModelData(editor:'QWidget *', model:'QAbstractItemModel *', index:'const QModelIndex &'):  pass
        #pxc>{
        #pxc>    if (((ShortcutEditor*)editor)->key != NULL) {
        #pxc>        QVariant value(*((ShortcutEditor*)editor)->key);
        #pxc>        model->setData(index, value, Qt::DisplayRole);
        #pxc>    }
        #pxc>}
        #pxc>
#pxh>
    #pxm-FUNC CH
    def slot_on_editor_key_pressed():  pass
        #pxc>{
        #pxc>    QWidget *editor = (QWidget*)this->sender();
        #pxc>    this->commitData(editor);
        #pxc>    this->closeEditor(editor, QAbstractItemDelegate::NoHint);
        #pxc>}
#pxm>CPPCLASS_END

#pxm-C_CPPCLASS class ColorIconEngine (QIconEngine):
class ColorIconEngine (QIconEngine):
    #pxh>QString color;
    #pxh>
    #pxh>ColorIconEngine() : QIconEngine(), color(QStringLiteral("black")) {}
    #pxh>
    #pxm-FUNC CH
    def paint(painter:'QPainter *', rect:'const QRect &', mode:'QIcon::Mode', state:'QIcon::State'):  pass
        #pxc>{ painter->fillRect(rect, QColor(this->color)); }
    #pxm-FUNC CH const
    def clone()->'ColorIconEngine *':  pass
        #pxc>{
        #pxc>    ColorIconEngine *cloned = new ColorIconEngine();
        #pxc>    cloned->color = color;
        #pxc>    return cloned;
        #pxc>}
#pxm>CPPCLASS_END

#pxm-CPPCLASS
class UIContainer:
    #pxh>Ui::MainWindow ui_main;
    #pxh>QLabel *label_selectmodel;
    #pxh>int active_plugin_group;
    #pxh>Ui::DialogPreferences ui_pref;
    #pxh>QStandardItemModel *liststore_movekeys;
    #pxh>QStandardItemModel *liststore_faces;
    #pxh>int liststore_faces_width;
    #pxh>ColorIconEngine *iconengine_color;
    #pxh>ColorIconEngine *iconengine_background_color;
    #pxh>Ui::DialogHelp ui_help;
    #pxh>Ui::AboutDialog ui_about;
    #pxh>int index_tab_about;
    #pxh>int index_tab_license;
    #pxh>QScrollBar *scrollbar;
    #pxh>QPropertyAnimation animation;
    #pxh>
    #pxm-FUNC CHP nogil
    def setupUi_main(window:'QMainWindow *', icon1:1, icon2:1, icon3:'const QIcon &', key1:1, key2:'const QKeySequence &'):  pass
        #pxc>{
            #pxc>// actions that belongs to no widget
            #pxc>QAction *action_jump_to_editbar = new QAction(window);
            #pxc>action_jump_to_editbar->setObjectName("action_jump_to_editbar");
            #pxc>action_jump_to_editbar->setShortcut(key1);
            #pxc>window->addAction(action_jump_to_editbar);
            #pxc>QAction *action_edit_cube = new QAction(window);
            #pxc>action_edit_cube->setObjectName("action_edit_cube");
            #pxc>action_edit_cube->setShortcut(key2);
            #pxc>window->addAction(action_edit_cube);
            
            #pxc>// Qt Designer code
            #pxc>ui_main.setupUi(window);
            
            #pxc>// ...
            #pxc>ui_main.splitter->setCollapsible(0, false);
            #pxc>ui_main.splitter->setStretchFactor(0, 1);
            #pxc>ui_main.splitter->setStretchFactor(1, 0);
            #pxc>ui_main.listwidget->setItemDelegate(new ModelSelectionItemDelegate());
            
            #pxc>// set icons
            #pxc>ui_main.button_edit_exec->setIcon(QIcon::fromTheme("system-run"));
            #pxc>ui_main.button_edit_clear->setIcon(QIcon::fromTheme("edit-clear"));
            #pxc>ui_main.action_challenge->setIcon(icon1);
            #pxc>ui_main.action_new_solved->setIcon(icon2);
            #pxc>ui_main.action_quit->setIcon(QIcon::fromTheme("application-exit"));
            #pxc>ui_main.action_rewind->setIcon(QIcon::fromTheme("media-seek-backward"));
            #pxc>ui_main.action_previous->setIcon(QIcon::fromTheme("media-skip-backward"));
            #pxc>ui_main.action_stop->setIcon(QIcon::fromTheme("media-playback-stop"));
            #pxc>ui_main.action_play->setIcon(QIcon::fromTheme("media-playback-start"));
            #pxc>ui_main.action_next->setIcon(QIcon::fromTheme("media-skip-forward"));
            #pxc>ui_main.action_forward->setIcon(QIcon::fromTheme("media-seek-forward"));
            #pxc>ui_main.action_mark_set->setIcon(QIcon::fromTheme("list-add"));
            #pxc>ui_main.action_mark_remove->setIcon(QIcon::fromTheme("list-remove"));
            #pxc>ui_main.action_selectmodel->setIcon(icon3);
            #pxc>ui_main.action_selectmodel_back->setIcon(QIcon::fromTheme("back"));
            #pxc>ui_main.action_preferences->setIcon(QIcon::fromTheme("document-properties"));
            #pxc>ui_main.action_info->setIcon(QIcon::fromTheme("help-about"));
            #pxc>ui_main.action_help->setIcon(QIcon::fromTheme("help"));
            
            #pxc>// widgets that are not created with Qt Designer: toolbar_play
            #pxc>ui_main.toolbar_play->addAction(ui_main.action_selectmodel);
            #pxc>ui_main.toolbar_play->addAction(ui_main.action_new_solved);
            #pxc>ui_main.toolbar_play->addAction(ui_main.action_challenge);
            #pxc>ui_main.toolbar_play->addSeparator();
            #pxc>ui_main.toolbar_play->addAction(ui_main.action_rewind);
            #pxc>ui_main.toolbar_play->addAction(ui_main.action_previous);
            #pxc>ui_main.toolbar_play->addAction(ui_main.action_stop);
            #pxc>ui_main.toolbar_play->addAction(ui_main.action_play);
            #pxc>ui_main.toolbar_play->addAction(ui_main.action_next);
            #pxc>ui_main.toolbar_play->addAction(ui_main.action_forward);
            #pxc>ui_main.toolbar_play->addAction(ui_main.action_mark_set);
            #pxc>ui_main.toolbar_play->addAction(ui_main.action_mark_remove);
            
            #pxc>// …: toolbar_selectmodel
            #pxc>ui_main.toolbar_selectmodel->addAction(ui_main.action_selectmodel_back);
            #pxc>label_selectmodel = new QLabel();
            #pxc>ui_main.toolbar_selectmodel->addWidget(label_selectmodel);
            #pxc>ui_main.toolbar_selectmodel->setVisible(false);
            
            #pxc>// …: toolbar_common
            #pxc>QWidget *spacer = new QWidget();
            #pxc>spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
            #pxc>ui_main.toolbar_common->addWidget(spacer);
            
            #pxc>// …: menu button
            #pxc>QToolButton *menubutton = new QToolButton(window);
            #pxc>menubutton->setIcon(QIcon::fromTheme("format-justify-fill")); //XXX: hmm
            #pxc>menubutton->setPopupMode(QToolButton::InstantPopup);
            #pxc>QMenu *menu = new QMenu(menubutton);
            #pxc>menu->addAction(ui_main.action_initial_state);
            #pxc>menu->addAction(ui_main.action_reset_rotation);
            #pxc>menu->addSeparator();
            #pxc>menu->addAction(ui_main.action_editbar);
            #pxc>menu->addAction(ui_main.action_statusbar);
            #pxc>menu->addSeparator();
            #pxc>menu->addAction(ui_main.action_preferences);
            #pxc>menu->addAction(ui_main.action_help);
            #pxc>menu->addAction(ui_main.action_info);
            #pxc>menu->addSeparator();
            #pxc>menu->addAction(ui_main.action_quit);
            #pxc>menubutton->setMenu(menu);
            #pxc>ui_main.toolbar_common->addWidget(menubutton);
            
            #pxc>// add action to main window for shortcuts
            #pxc>window->addAction(ui_main.action_challenge);
            #pxc>window->addAction(ui_main.action_new_solved);
            #pxc>window->addAction(ui_main.action_quit);
            #pxc>window->addAction(ui_main.action_selectmodel);
            #pxc>window->addAction(ui_main.action_initial_state);
            #pxc>window->addAction(ui_main.action_reset_rotation);
            #pxc>window->addAction(ui_main.action_preferences);
            #pxc>window->addAction(ui_main.action_statusbar);
            #pxc>window->addAction(ui_main.action_info);
            #pxc>window->addAction(ui_main.action_rewind);
            #pxc>window->addAction(ui_main.action_rewind);
            #pxc>window->addAction(ui_main.action_previous);
            #pxc>window->addAction(ui_main.action_previous);
            #pxc>window->addAction(ui_main.action_stop);
            #pxc>window->addAction(ui_main.action_stop);
            #pxc>window->addAction(ui_main.action_play);
            #pxc>window->addAction(ui_main.action_play);
            #pxc>window->addAction(ui_main.action_next);
            #pxc>window->addAction(ui_main.action_next);
            #pxc>window->addAction(ui_main.action_forward);
            #pxc>window->addAction(ui_main.action_forward);
            #pxc>window->addAction(ui_main.action_mark_set);
            #pxc>window->addAction(ui_main.action_mark_set);
            #pxc>window->addAction(ui_main.action_mark_remove);
            #pxc>window->addAction(ui_main.action_mark_remove);
            #pxc>window->addAction(ui_main.action_editbar);
            #pxc>window->addAction(ui_main.action_help);
            #pxc>window->addAction(ui_main.action_help);
            
            #pxc>// rest
            #pxc>disable_tooltips();
            #pxc>active_plugin_group = 0;
        #pxc>}
    #pxm-FUNC CHP
    def disable_tooltips():  pass
        #pxc>{
            #pxc>//pita: If a action has no tooltip, the appropriate toolbutton uses the actions text for the tooltip.
            #pxc>//      To remove tooltips you have to remove the tooltips for the appropriate toolbutton,
            #pxc>//      but every time you change something on the action, the button will recreate the tooltip
            #pxc>ui_main.toolbar_play->widgetForAction(ui_main.action_rewind)->setToolTip(QStringLiteral(""));
            #pxc>ui_main.toolbar_play->widgetForAction(ui_main.action_previous)->setToolTip(QStringLiteral(""));
            #pxc>ui_main.toolbar_play->widgetForAction(ui_main.action_stop)->setToolTip(QStringLiteral(""));
            #pxc>ui_main.toolbar_play->widgetForAction(ui_main.action_play)->setToolTip(QStringLiteral(""));
            #pxc>ui_main.toolbar_play->widgetForAction(ui_main.action_next)->setToolTip(QStringLiteral(""));
            #pxc>ui_main.toolbar_play->widgetForAction(ui_main.action_forward)->setToolTip(QStringLiteral(""));
        #pxc>}
    #pxm-FUNC CHP
    def set_shortcuts(key1:1, key2:1, key3:1, key4:'const QKeySequence &'):  pass
        #pxc>{
            #pxc>ui_main.action_selectmodel->setShortcut(key1);
            #pxc>ui_main.action_initial_state->setShortcut(key2);
            #pxc>ui_main.action_reset_rotation->setShortcut(key3);
            #pxc>ui_main.action_preferences->setShortcut(key4);
        #pxc>}
    #pxm-FUNC CHP
    def add_widgets(window:'QMainWindow *', edit:'QLineEdit *', drawing:'QOpenGLWidget *'):  pass
        #pxc>{
            #pxc>edit->setObjectName("edit_moves");
            #pxc>edit->setFrame(false);
            #pxc>ui_main.layout_moves->insertWidget(1, edit);
            #pxc>drawing->setObjectName("drawingarea");
            #pxc>ui_main.verticalLayout->addWidget(drawing);
            #pxc>window->setTabOrder(edit, drawing);
            #pxc>window->setTabOrder(drawing, ui_main.box_sidepane);
            #pxc>drawing->setFocus(Qt::OtherFocusReason);
        #pxc>}
        
    #pxm-FUNC CHP nogil
    def set_toolbar_visible(visible:bool):  pass
        #pxc>{ ui_main.toolbar_play->setVisible(visible); }
    #pxm-FUNC CHP nogil
    def set_frame_editbar_visible(visible:bool):  pass
        #pxc>{ ui_main.frame_editbar->setVisible(visible); }
    #pxm-FUNC CHP nogil
    def set_statusbar_visible(visible:bool):  pass
        #pxc>{ ui_main.statusbar->setVisible(visible); }
    #pxm-FUNC CHP nogil
    def hide_controls(): pass
        #pxc>{
            #pxc>ui_main.toolbar_play->setVisible(false);
            #pxc>ui_main.toolbar_common->setVisible(false);
            #pxc>ui_main.frame_editbar->setVisible(false);
            #pxc>ui_main.statusbar->setVisible(false);
            #pxc>ui_main.box_sidepane->setVisible(false);
        #pxc>}
        
    #pxm-FUNC CHP nogil
    def set_visible(debug_text_visible:bool, editbar_visible:bool, statusbar_visible:bool):  pass
        #pxc>{
            #pxc>ui_main.label_debug_text->setVisible(debug_text_visible);
            #pxc>ui_main.action_editbar->setChecked(editbar_visible);
            #pxc>ui_main.action_statusbar->setChecked(statusbar_visible);
            #pxc>ui_main.frame_editbar->setVisible(editbar_visible);
            #pxc>ui_main.statusbar->setVisible(statusbar_visible);
        #pxc>}
        
    #pxm-FUNC CHP nogil
    def get_splitter_sizes(s1:'int &', s2:'int &'):  pass
        #pxc>{
            #pxc>QList<int> list(ui_main.splitter->sizes());
            #pxc>s1 = list.at(0);
            #pxc>s2 = list.at(1);
        #pxc>}
    #pxm-FUNC CHP nogil
    def set_splitter_sizes(s1:int, s2:int):  pass
        #pxc>{
            #pxc>QList<int> list;
            #pxc>list.append(s1);
            #pxc>list.append(s2);
            #pxc>ui_main.splitter->setSizes(list);
        #pxc>}
    #pxm-FUNC CHP nogil
    def splitter_update_minimumsize():  pass
        #pxc>{
            #pxc>int w0, w1;
            #pxc>get_splitter_sizes(w0, w1);
            #pxc>QSize s0 = ui_main.splitter->widget(0)->minimumSizeHint();
            #pxc>QSize s1 = ui_main.splitter->widget(1)->minimumSizeHint();
            #pxc>int w = s0.width() + ui_main.splitter->handleWidth();
            #pxc>int h = std::max(s0.height(), s1.height());
            #pxc>w += w1==0 ? 6 : s1.width();
            #pxc>ui_main.splitter->setMinimumSize(w, h);
        #pxc>}
        
    #pxm-FUNC CHP nogil
    def set_debug_text(text:str):  pass
        #pxc>{ ui_main.label_debug_text->setText(text); }
        
    #pxm-FUNC CHP nogil
    def set_toolbar_state(a:int, b:int, c:int, d:int, e:int):  pass
        #pxc>{
            #pxc>ui_main.action_rewind->setEnabled(a);
            #pxc>ui_main.action_previous->setEnabled(a);
            #pxc>ui_main.action_play->setEnabled(b);
            #pxc>ui_main.action_next->setEnabled(b);
            #pxc>ui_main.action_forward->setEnabled(b);
            #pxc>ui_main.action_mark_set->setEnabled(c);
            #pxc>ui_main.action_mark_remove->setEnabled(c);
            #pxc>ui_main.action_stop->setVisible(d);
            #pxc>ui_main.action_play->setVisible(!d);
            #pxc>ui_main.action_mark_set->setVisible(e);
            #pxc>ui_main.action_mark_remove->setVisible(!e);
            #pxc>disable_tooltips();
        #pxc>}
        
    #pxm-FUNC CHP nogil
    def clear_sidepane():  pass
        #pxc>{
            #pxc>QLayoutItem *child;
            #pxc>while ((child = ui_main.layout_sidepane->takeAt(0)) != 0) {
                #pxc>delete child;
            #pxc>}
        #pxc>}
    #pxm-FUNC CHP nogil
    def create_sidepane_button(text:str)->'QPushButton *':  pass
        #pxc>{
            #pxc>QPushButton *button = new QPushButton(ui_main.box_sidepane);
            #pxc>button->setText(text);
            #pxc>button->setFlat(true);
            #pxc>button->setFocusPolicy(Qt::TabFocus);
            #pxc>ui_main.layout_sidepane->addWidget(button);
            #pxc>return button;
        #pxc>}
    #pxm-FUNC CHP nogil
    def create_sidepane_treeview(treestore:'QStandardItemModel *', i:int)->'QTreeView *':  pass
        #pxc>{
            #pxc>QTreeView *treeview = new QTreeView(ui_main.box_sidepane);
            #pxc>treeview->setFrameShape(QFrame::NoFrame);
            #pxc>treeview->setEditTriggers(QAbstractItemView::NoEditTriggers);
            #pxc>treeview->setUniformRowHeights(true);
            #pxc>treeview->setAnimated(true);
            #pxc>treeview->setHeaderHidden(true);
            #pxc>treeview->hide();
            #pxc>treeview->setModel(treestore);
            #pxc>treeview->setRootIndex(treestore->index(i, 0));
            #pxc>ui_main.layout_sidepane->addWidget(treeview);
            #pxc>return treeview;
        #pxc>}
    #pxm-FUNC CHP nogil
    def set_active_plugin_group(i:int):  pass
        #pxc>{
            #pxc>QLayoutItem *item_treeview;
            #pxc>if (i == -1)  i = active_plugin_group;
            #pxc>item_treeview = ui_main.layout_sidepane->itemAt(active_plugin_group*2+1);
            #pxc>if (item_treeview != NULL)
                #pxc>item_treeview->widget()->hide();
            #pxc>item_treeview = ui_main.layout_sidepane->itemAt(i*2+1);
            #pxc>if (item_treeview != NULL)
                #pxc>item_treeview->widget()->show();
            #pxc>active_plugin_group = i;
        #pxc>}
    #pxm-FUNC CHP nogil
    def set_active_plugin_group_by_obj(obj:'QObject *'):  pass
        #pxc>{
            #pxc>int i = ui_main.layout_sidepane->indexOf((QWidget*)obj);
            #pxc>this->set_active_plugin_group(i/2);
        #pxc>}
    #pxm-FUNC CHP nogil
    def get_plugin_group_count()->int:  pass
        #pxc>{ return ui_main.layout_sidepane->count() / 2; }
    #pxm-FUNC CHP nogil
    def root_index(i:int)->'QModelIndex':  pass
        #pxc>{ return ((QTreeView*)ui_main.layout_sidepane->itemAt(i*2+1)->widget())->rootIndex(); }
    #pxm-FUNC CHP nogil
    def hide_row(i:int, hide:bool):  pass
        #pxc>{
            #pxc>QWidget *button = ui_main.layout_sidepane->itemAt(i*2)->widget();
            #pxc>if (hide) {
            #pxc>    button->hide();
            #pxc>    if (i == active_plugin_group)  set_active_plugin_group(0);
            #pxc>} else {
            #pxc>    button->show();
            #pxc>}
        #pxc>}
    #pxm-FUNC CHP nogil
    def set_row_hidden(i:int, row:int, index:'const QModelIndex &', hide:bool):  pass
        #pxc>{ ((QTreeView*)ui_main.layout_sidepane->itemAt(i*2+1)->widget())->setRowHidden(row, index, hide); }
    #pxm-FUNC CHP nogil
    def splitter_pos()->int:  pass
        #pxc>{ return ui_main.splitter->sizes()[0]; }
        
    #pxh>// ####
    #pxm-FUNC CHP nogil
    def setupUi_pref(window:'QDialog *', speed:int, speed_min:int, speed_max:int, mirror_min:int, mirror_max:int, _movekeys:'QStandardItemModel *'):  pass
        #pxc>{
            #pxc>liststore_movekeys = _movekeys;
            #pxc>liststore_movekeys->setObjectName("liststore_movekeys");
            #pxc>liststore_faces = new QStandardItemModel(window);
            #pxc>liststore_faces->setObjectName("liststore_faces");
            #pxc>
            #pxc>ui_pref.setupUi(window);
            #pxc>
            #pxc>ui_pref.button_animspeed_reset->setIcon(QIcon::fromTheme("edit-clear"));
            #pxc>ui_pref.button_shader_reset->setIcon(QIcon::fromTheme("edit-clear"));
            #pxc>ui_pref.button_antialiasing_reset->setIcon(QIcon::fromTheme("edit-clear"));
            #pxc>ui_pref.button_mirror_faces_reset->setIcon(QIcon::fromTheme("edit-clear"));
            #pxc>ui_pref.button_movekey_add->setIcon(QIcon::fromTheme("list-add"));
            #pxc>ui_pref.button_movekey_remove->setIcon(QIcon::fromTheme("list-remove"));
            #pxc>ui_pref.button_movekey_reset->setIcon(QIcon::fromTheme("document-revert"));
            #pxc>ui_pref.button_color_reset->setIcon(QIcon::fromTheme("edit-clear"));
            #pxc>ui_pref.button_image_reset->setIcon(QIcon::fromTheme("edit-clear"));
            #pxc>ui_pref.button_background_color_reset->setIcon(QIcon::fromTheme("edit-clear"));
            #pxc>
            #pxc>ui_pref.buttonBox->button(QDialogButtonBox::Close)->setDefault(true);
            #pxc>ui_pref.label_needs_restarted->setVisible(false);
            #pxc>QPalette pal(ui_pref.label_needs_restarted->palette());
            #pxc>pal.setColor(QPalette::WindowText, QColor(170, 0, 0));
            #pxc>ui_pref.label_needs_restarted->setPalette(pal);
            #pxc>
            #pxc>// graphic tab
            #pxc>ui_pref.slider_animspeed->setRange(speed_min, speed_max);
            #pxc>ui_pref.slider_animspeed->setValue(speed);
            #pxc>ui_pref.spinbox_mirror_faces->setRange(mirror_min, mirror_max);
            #pxc>
            #pxc>// keys tab
            #pxc>liststore_movekeys->setColumnCount(2);
            #pxc>ui_pref.listview_movekeys->setModel(liststore_movekeys);
            #pxc>ShortcutDelegate *shortcut_delegate = new ShortcutDelegate(ui_pref.listview_movekeys);
            #pxc>ui_pref.listview_movekeys->setItemDelegateForColumn(1, shortcut_delegate);
            #pxc>
            #pxc>// theme tab
            #pxc>liststore_faces_width = 30;
            #pxc>iconengine_color = new ColorIconEngine();
            #pxc>ui_pref.button_color->setIcon(QIcon(iconengine_color));
            #pxc>int height = ui_pref.button_color->iconSize().height();
            #pxc>ui_pref.button_color->setIconSize(
            #pxc>        QSize(height * ui_pref.button_color->width() / ui_pref.button_color->height(), height));
            #pxc>ui_pref.button_color->setText(QStringLiteral(""));
            #pxc>iconengine_background_color = new ColorIconEngine();
            #pxc>ui_pref.button_background_color->setIcon(QIcon(iconengine_background_color));
            #pxc>height = ui_pref.button_background_color->iconSize().height();
            #pxc>ui_pref.button_background_color->setIconSize(
            #pxc>        QSize(height * ui_pref.button_background_color->width() / ui_pref.button_background_color->height(), height));
            #pxc>ui_pref.button_background_color->setText(QStringLiteral(""));
        #pxc>}
        
    #pxm-FUNC CHP nogil
    def preferences_block_signals(block:bool):  pass
        #pxc>{
            #pxc>ui_pref.combobox_shader->blockSignals(block);
            #pxc>ui_pref.combobox_samples->blockSignals(block);
            #pxc>liststore_movekeys->blockSignals(block);
        #pxc>}
    #pxm-FUNC CHP nogil
    def combobox_add_shaderitem(name:str, nick:str):  pass
        #pxc>{ ui_pref.combobox_shader->addItem(name, nick); }
    #pxm-FUNC CHP nogil
    def combobox_add_samplesitem(name:str, nick:str):  pass
        #pxc>{ ui_pref.combobox_samples->addItem(name, nick); }
    #pxm-FUNC CHP nogil
    def add_movekey_row():  pass
        #pxc>{
            #pxc>int row = ui_pref.listview_movekeys->currentIndex().row();
            #pxc>liststore_movekeys->insertRow(row);
            #pxc>liststore_movekeys->setItem(row, 0, new QStandardItem(""));
            #pxc>liststore_movekeys->setItem(row, 1, new QStandardItem(""));
            #pxc>QModelIndex index = liststore_movekeys->index(row, 0);
            #pxc>ui_pref.listview_movekeys->setCurrentIndex(index);
            #pxc>ui_pref.listview_movekeys->edit(index);
        #pxc>}
    #pxm-FUNC CHP nogil
    def remove_movekey_row():  pass
        #pxc>{
            #pxc>int row = ui_pref.listview_movekeys->currentIndex().row();
            #pxc>liststore_movekeys->takeRow(row);
        #pxc>}
    #pxm-FUNC CHP nogil
    def add_liststore_faces_row(name:str, key:str):  pass
        #pxc>{
            #pxc>QStandardItem *item = new QStandardItem(name);
            #pxc>item->setData(QVariant(key));
            #pxc>liststore_faces->appendRow(item);
            #pxc>//XXX: workaround, listview_faces should automatically set to the correct width
            #pxc>QFontMetrics fm(ui_pref.listview_faces->font());
            #pxc>int width = fm.width(name) + 20;  // 20 for the scroll bar
            #pxc>if (liststore_faces_width < width)  liststore_faces_width = width;
        #pxc>}
    #pxm-FUNC CHP nogil
    def finalize_liststore_faces(window:'QWidget *'):  pass
        #pxc>{
            #pxc>ui_pref.listview_faces->setMaximumWidth(liststore_faces_width);
            #pxc>ui_pref.listview_faces->setModel(liststore_faces);
            #pxc>QObject::connect(ui_pref.listview_faces->selectionModel(),
            #pxc>                   SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)),
            #pxc>                 window,
            #pxc>                   SLOT(_on_listview_faces_currentRowChanged(const QModelIndex &)));
            #pxc>ui_pref.listview_faces->setCurrentIndex(liststore_faces->index(0, 0));
        #pxc>}
    #pxm-FUNC CHP nogil
    def get_liststore_faces_facekey(index:'const QModelIndex &')->str:  pass
        #pxc>{ return liststore_faces->itemFromIndex(index)->data().toString(); }
    #pxm-FUNC CHP nogil
    def set_button_color(color:str):  pass
        #pxc>{
            #pxc>iconengine_color->color = color;
            #pxc>ui_pref.button_color->update();
        #pxc>}
    #pxm-FUNC CHP nogil
    def color_dialog(parent:'QWidget *', color:str)->str:  pass
        #pxc>{
            #pxc>QColorDialog dialog(parent);
            #pxc>dialog.setOption(QColorDialog::DontUseNativeDialog);
            #pxc>dialog.setCurrentColor(QColor(color));
            #pxc>if (dialog.exec() == QDialog::Accepted)
                #pxc>return dialog.currentColor().name();
            #pxc>return QString();
        #pxc>}
    #pxm-FUNC CHP nogil
    def set_imagemode(imagemode:int):  pass
        #pxc>{
            #pxc>if (imagemode == 0)
                #pxc>ui_pref.radiobutton_tiled->setChecked(true);
            #pxc>else if (imagemode == 1)
                #pxc>ui_pref.radiobutton_mosaic->setChecked(true);
        #pxc>}
    #pxm-FUNC CHP nogil
    def add_combobox_image_item(icon:'const QIcon &', text:str, filename:str):  pass
        #pxc>{ ui_pref.combobox_image->addItem(icon, text, filename); }
    #pxm-FUNC CHP nogil
    def set_combobox_image(index_icon:int, icon:'const QIcon &', index:int):  pass
        #pxc>{
            #pxc>ui_pref.combobox_image->setItemIcon(index_icon, icon);
            #pxc>if (index >= 0)  ui_pref.combobox_image->setCurrentIndex(index);
        #pxc>}
    #pxh>
    #pxm-FUNC CHP nogil
    def set_button_background_color(color:str):  pass
        #pxc>{
            #pxc>iconengine_background_color->color = color;
            #pxc>ui_pref.button_background_color->update();
        #pxc>}
    
    #pxm-FUNC CHP nogil
    def fill_page(items:'QVariant', title:str):  pass
        #pxc>{
            #pxc>ui_main.listwidget->clear();
            #pxc>QList<QObject*> list = items.value<QList<QObject*> >();
            #pxc>for (int i=0; i < list.size(); ++i) {
                #pxc>QObject *obj = list.at(i);
                #pxc>QString text = obj->property("text").value<QString>();
                #pxc>QString filename = obj->property("key").value<QString>();
                #pxc>QListWidgetItem *item = new QListWidgetItem(QIcon(filename), text);
                #pxc>item->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
                #pxc>ui_main.listwidget->addItem(item);
            #pxc>}
            #pxc>label_selectmodel->setText(title);
        #pxc>}
    #pxm-FUNC CHP nogil
    def set_page(i:int):  pass
        #pxc>{
            #pxc>ui_main.stackedwidget->setCurrentIndex(i);
            #pxc>ui_main.toolbar_play->setVisible(i==0);
            #pxc>ui_main.toolbar_selectmodel->setVisible(i!=0);
        #pxc>}
        
    #pxm-FUNC CHP nogil
    def setupUi_help(window:'QDialog *', helptext:str):  pass
        #pxc>{
            #pxc>ui_help.setupUi(window);
            #pxc>ui_help.text_help->setHtml(helptext);
        #pxc>}
        
    #pxm-FUNC CHP nogil
    def setupUi_about(window:'QDialog *'):  pass
        #pxc>{
            #pxc>ui_about.setupUi(window);
            #pxc>index_tab_about = ui_about.tab_widget->indexOf(ui_about.tab_about);
            #pxc>index_tab_license = ui_about.tab_widget->indexOf(ui_about.tab_license);
            #pxc>// About tab animation
            #pxc>scrollbar = ui_about.text_translators->verticalScrollBar();
            #pxc>animation.setTargetObject(scrollbar);
            #pxc>animation.setPropertyName(QByteArray("value"));
            #pxc>animation.setLoopCount(-1);
            #pxc>ui_about.text_translators->viewport()->installEventFilter(window);
        #pxc>}
    #pxm-FUNC CHP nogil
    def fill_header(fileName:str, appname:str, version:str, desc:str):  pass
        #pxc>{
            #pxc>ui_about.label_icon->setPixmap(QPixmap(fileName));
            #pxc>ui_about.label_appname->setText(appname);
            #pxc>ui_about.label_version->setText(version);
            #pxc>ui_about.label_description->setText(desc);
        #pxc>}
    #pxm-FUNC CHP nogil
    def fill_about_tab(copyr:str, website:str, translators:str):  pass
        #pxc>{
            #pxc>ui_about.label_copyright->setText(copyr);
            #pxc>ui_about.label_website->setText(website);
            #pxc>ui_about.text_translators->setHtml(translators);
        #pxc>}
    #pxm-FUNC CHP nogil
    def fill_contribute_tab(contribute:str):  pass
        #pxc>{ ui_about.label_contribute->setText(contribute); }
    #pxm-FUNC CHP nogil
    def fill_license_tab(license_short:str, license_notfound:bool, license_full:str):  pass
        #pxc>{
            #pxc>ui_about.text_license_short->hide();
            #pxc>ui_about.text_license_full->hide();
            #pxc>ui_about.text_license_short->setHtml(license_short);
            #pxc>if (license_notfound)  ui_about.text_license_full->setLineWrapMode(QTextEdit::WidgetWidth);
            #pxc>ui_about.text_license_full->setHtml(license_full);
        #pxc>}
    #pxm-FUNC CHP nogil
    def tab_widget_currentChanged(index:int):  pass
        #pxc>{
            #pxc>if (index == index_tab_about) {
                #pxc>animation.resume();
                #pxc>scrollbar->hide();
            #pxc>} else {
                #pxc>animation.pause();
                #pxc>scrollbar->show();
            #pxc>}
            #pxc>if (index == index_tab_license) {
                #pxc>ui_about.text_license_short->setVisible(true);
                #pxc>ui_about.text_license_full->setVisible(false);
            #pxc>}
        #pxc>}
    #pxm-FUNC CHP nogil
    def update_animation(first:bool):  pass
        #pxc>{
            #pxc>int smin, smax;
            #pxc>if (first and animation.state() != QAbstractAnimation::Stopped) return;
            #pxc>smin = scrollbar->minimum();
            #pxc>smax = scrollbar->maximum();
            #pxc>if (smax > smin) {
                #pxc>animation.setDuration((smax-smin) * 40);
                #pxc>animation.setKeyValueAt(0., smin);
                #pxc>animation.setKeyValueAt(0.04, smin);
                #pxc>animation.setKeyValueAt(0.50, smax);
                #pxc>animation.setKeyValueAt(0.54, smax);
                #pxc>animation.setKeyValueAt(1., smin);
            #pxc>}
            #pxc>if (first) {
                #pxc>scrollbar->hide();
                #pxc>animation.start();
            #pxc>}
        #pxc>}
    #pxm-FUNC CHP nogil
    def event_filter_stop_animation(event:'QEvent *'):  pass
        #pxc>{
            #pxc>//assert watched == ui_about.text_translators.viewport()
            #pxc>if ((event->type() == QEvent::MouseButtonPress) || (event->type() == QEvent::Wheel)) {
                #pxc>animation.pause();
                #pxc>scrollbar->show();
            #pxc>}
        #pxc>}
    #pxm-FUNC CHP nogil
    def show_full_license(local:bool, url:'const QUrl &'):  pass
        #pxc>{
            #pxc>if (local) {
                #pxc>ui_about.text_license_short->setVisible(false);
                #pxc>ui_about.text_license_full->setVisible(true);
            #pxc>} else
                #pxc>QDesktopServices::openUrl(url);
        #pxc>}

#pxm>CPPCLASS_END
    

#pxm-FUNC CHP
def mk_qstr(pstr:'const char *', length:int)->str:  return pstr
    #pxc>{ return QString::fromUtf8(pstr, length); }
    
#pxm>DEDENT

#px/cdef UIContainer qtui
qtui = UIContainer()

#pxm-FUNC PD
def init_gettext(gettext):
    global _
    _ = gettext
#px/cdef QString gettext_translate(const char *text, const char *disambiguation) with gil:
def gettext_translate(text, disambiguation):
    pytext = _(text.decode('utf-8')).encode('utf-8')
    return mk_qstr(pytext, len(pytext))
    
    
#XXX: Cython cannot export C functions, so this wrapper functions are needed.
#TODO: Makro for generating wrapper functions or exported function pointers

#pxm-FUNC PD
def setupUi_main(window:'QMainWindow *', icon1:1, icon2:1, icon3:'const QIcon &', key1:1, key2:'const QKeySequence &', editbar_visible:bool, statusbar_visible:bool):
    qtui.setupUi_main(window, icon1, icon2, icon3, key1, key2)
    qtui.set_visible(debug & (DEBUG_DRAW | DEBUG_FPS), editbar_visible, statusbar_visible)
    
#pxm-FUNC PD
def setupUi_pref(window:'QDialog *', speed:int, speed_min:int, speed_max:int, mirror_min:int, mirror_max:int, liststore_movekeys:'QStandardItemModel *'):
    qtui.setupUi_pref(window, speed, speed_min, speed_max, mirror_min, mirror_max, liststore_movekeys)
    
#pxm-FUNC PD
def setupUi_help(window:'QDialog *', helptext:str):
    qtui.setupUi_help(window, helptext)
    
#pxm-FUNC PD
def setupUi_about(window:'QDialog *'):
    qtui.setupUi_about(window)
    
#pxm-FUNC PD
def set_shortcuts(key1:1, key2:1, key3:1, key4:'const QKeySequence &'):
    qtui.set_shortcuts(key1, key2, key3, key4)
#pxm-FUNC PD
def add_widgets(window:'QMainWindow *', edit:'QLineEdit *', drawing:'QOpenGLWidget *'):
    qtui.add_widgets(window, edit, drawing)
    
#pxm-FUNC PD nogil
def set_toolbar_visible(visible:bool):
    qtui.set_toolbar_visible(visible)
#pxm-FUNC PD nogil
def set_frame_editbar_visible(visible:bool):
    qtui.set_frame_editbar_visible(visible)
#pxm-FUNC PD nogil
def set_statusbar_visible(visible:bool):
    qtui.set_statusbar_visible(visible)
#pxm-FUNC PD nogil
def hide_controls():
    qtui.hide_controls()
#pxm-FUNC PD nogil
def get_splitter_sizes(s1:'int &', s2:'int &'):
    qtui.get_splitter_sizes(s1, s2)
#pxm-FUNC PD nogil
def set_splitter_sizes(s1:int, s2:int):
    qtui.set_splitter_sizes(s1, s2)
#pxm-FUNC PD nogil
def splitter_update_minimumsize():
    qtui.splitter_update_minimumsize()
#pxm-FUNC PD nogil
def set_debug_text(text:str):
    qtui.set_debug_text(text)
    
#pxm-FUNC PD nogil
def set_toolbar_state(a:int, b:int, c:int, d:int, e:int):
    qtui.set_toolbar_state(a, b, c, d, e)
    
#pxm-FUNC PD nogil
def clear_sidepane():
    qtui.clear_sidepane()
#pxm-FUNC PD nogil
def create_sidepane_button(text:str)->'QPushButton *':
    return qtui.create_sidepane_button(text)
#pxm-FUNC PD nogil
def create_sidepane_treeview(treestore:'QStandardItemModel *', i:int)->'QTreeView *':
    return qtui.create_sidepane_treeview(treestore, i)
#pxm-FUNC PD nogil
def set_active_plugin_group(i:int):
    qtui.set_active_plugin_group(i)
#pxm-FUNC PD nogil
def set_active_plugin_group_by_obj(obj:'QObject *'):
    qtui.set_active_plugin_group_by_obj(obj)
#pxm-FUNC PD nogil
def get_plugin_group_count()->int:
    return qtui.get_plugin_group_count()
#pxm-FUNC PD nogil
def root_index(i:int)->'QModelIndex':
    return qtui.root_index(i)
#pxm-FUNC PD nogil
def hide_row(i:int, hide:bool):
    qtui.hide_row(i, hide)
#pxm-FUNC PD nogil
def set_row_hidden(treeview:int, row:int, index:'const QModelIndex &', hide:bool):
    qtui.set_row_hidden(treeview, row, index, hide)
#pxm-FUNC PD nogil
def splitter_pos()->int:
    return qtui.splitter_pos()
    
#pxm-FUNC PD nogil
def preferences_block_signals(block:bool):
    qtui.preferences_block_signals(block)
#pxm-FUNC PD nogil
def combobox_add_shaderitem(name:str, nick:str):
    qtui.combobox_add_shaderitem(name, nick)
#pxm-FUNC PD nogil
def combobox_add_samplesitem(name:str, nick:str):
    qtui.combobox_add_samplesitem(name, nick)
#pxm-FUNC PD nogil
def add_movekey_row():
    qtui.add_movekey_row()
#pxm-FUNC PD nogil
def remove_movekey_row():
    qtui.remove_movekey_row()
#pxm-FUNC PD nogil
def add_liststore_faces_row(name:str, key:str):
    qtui.add_liststore_faces_row(name, key)
#pxm-FUNC PD nogil
def finalize_liststore_faces(window:'QWidget *'):
    qtui.finalize_liststore_faces(window)
#pxm-FUNC PD nogil
def get_liststore_faces_facekey(index:'const QModelIndex &')->str:
    return qtui.get_liststore_faces_facekey(index)
#pxm-FUNC PD nogil
def set_button_color(color:str):
    qtui.set_button_color(color)
#pxm-FUNC PD nogil
def color_dialog(parent:'QWidget *', color:str)->str:
    return qtui.color_dialog(parent, color)
#pxm-FUNC PD nogil
def set_imagemode(imagemode:int):
    qtui.set_imagemode(imagemode)
#pxm-FUNC PD nogil
def add_combobox_image_item(icon:'const QIcon &', text:str, filename:str):
    qtui.add_combobox_image_item(icon, text, filename)
#pxm-FUNC PD nogil
def set_combobox_image(index_icon:int, icon:'const QIcon &', index:int):
    qtui.set_combobox_image(index_icon, icon, index)
#pxm-FUNC PD nogil
def set_button_background_color(color:str):
    qtui.set_button_background_color(color)
    
#pxm-FUNC PD nogil
def fill_page(items:'QVariant', title:str):
    qtui.fill_page(items, title)
#pxm-FUNC PD nogil
def set_page(i:int):
    qtui.set_page(i)
    
#pxm-FUNC PD nogil
def fill_header(fileName:str, appname:str, version:str, desc:str):
    qtui.fill_header(fileName, appname, version, desc)
#pxm-FUNC PD nogil
def fill_about_tab(copyr:str, website:str, translators:str):
    qtui.fill_about_tab(copyr, website, translators)
#pxm-FUNC PD nogil
def fill_contribute_tab(contribute:str):
    qtui.fill_contribute_tab(contribute)
#pxm-FUNC PD nogil
def fill_license_tab(license_short:str, license_notfound:bool, license_full:str):
    qtui.fill_license_tab(license_short, license_notfound, license_full)
#pxm-FUNC PD nogil
def tab_widget_currentChanged(index:int):
    qtui.tab_widget_currentChanged(index)
#pxm-FUNC PD nogil
def update_animation(first:bool):
    qtui.update_animation(first)
#pxm-FUNC PD nogil
def event_filter_stop_animation(event:'QEvent *'):
    qtui.event_filter_stop_animation(event)
#pxm-FUNC PD nogil
def show_full_license(local:bool, url:'const QUrl &'):
    qtui.show_full_license(local, url)
    

