/* menutreeui.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2013-2023 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "menutreeui.hh"
#include "worker.h"
#include "nwc_path.hh"
#include "menutree.hh"
#include "aguix/aguix.h"
#include "aguix/awindow.h"
#include "aguix/button.h"
#include "aguix/fieldlistview.h"
#include "aguix/stringgadget.h"
#include "aguix/textview.h"
#include "aguix/utf8.hh"
#include "aguix/choosebutton.h"
#include <algorithm>
#include <iostream>
#include "prefixdb.hh"
#include <memory>
#include "worker_locale.h"
#include "pers_kvp.hh"

MenuTreeUI::MenuTreeUI( AGUIX *aguix )
    : m_aguix( aguix ),
      m_menu( NULL ),
      m_current_dehighlight_entry( NULL ),
      m_show_recently_used( false )
{
    std::string cfgfile = Worker::getWorkerConfigDir();
    std::string recently_used_file;
#ifdef USEOWNCONFIGFILES
    recently_used_file = NWC::Path::join( cfgfile, "menu-recent2" );
    cfgfile = NWC::Path::join( cfgfile, "menu-choices2" );
#else
    recently_used_file = NWC::Path::join( cfgfile, "menu-recent" );
    cfgfile = NWC::Path::join( cfgfile, "menu-choices" );
#endif

    m_pdb = std::unique_ptr< PrefixDB >( new PrefixDB( cfgfile ) );
    m_recently_used = std::make_shared< PersistentStringList >( recently_used_file );
}

MenuTreeUI::~MenuTreeUI()
{
    delete m_menu;
}

void MenuTreeUI::setMenuTree( MenuTree *menu )
{
    delete m_menu;
    m_menu = menu;
}

static MenuTreeNode *findNode( MenuTreeNode *start_node,
                               const MenuTreeNode *node_to_search )
{
    if ( ! start_node ||
         ! node_to_search ) {
        return NULL;
    }

    for ( const auto &node : *start_node ) {
        if ( node == node_to_search ) {
            return node;
        }
        if ( node->hasChildren() ) {
            auto res = findNode( node, node_to_search );
            if ( res ) {
                return res;
            }
        }
    }

    return NULL;
}

void MenuTreeUI::show( bool show_recently_used, MenuTreeNode *initial_node )
{
    const AWindow *twin = NULL;

    if ( m_aguix->getTransientWindow() != NULL ) {
        twin = m_aguix->getTransientWindow();
    }

    AWindow *mainwin = new AWindow( m_aguix, 10, 10, 50, 10, catalog.getLocale( 1303 ) );
    mainwin->create();

    if ( twin != NULL ) {
        mainwin->setTransientForAWindow( twin );
    }

    AContainer *maincont = mainwin->setContainer( new AContainer( mainwin, 1, 6 ), true );

    maincont->setMinSpace( 5 );
    maincont->setMaxSpace( 5 );

    RefCount<AFontWidth> lencalc( new AFontWidth( m_aguix, NULL ) );
    auto help_ts = std::make_shared< TextStorageString >( catalog.getLocale( 1007 ), lencalc );
    TextView *help_tv = (TextView*)maincont->add( new TextView( m_aguix,
                                                                0, 0, 50, 80, "", help_ts ),
                                                  0, 0, AContainer::CO_INCW );
    help_tv->setLineWrap( true );
    help_tv->maximizeX( 500 );
    help_tv->maximizeYLines( 10 );
    help_tv->showFrame( false );
    maincont->readLimits();
    help_tv->show();
    help_tv->setAcceptFocus( false );

    TextView::ColorDef tv_cd = help_tv->getColors();
    tv_cd.setBackground( 0 );
    tv_cd.setTextColor( 1 );
    help_tv->setColors( tv_cd );

    ChooseButton *recently_cb = maincont->addWidget( new ChooseButton( m_aguix,
                                                                       0, 0,
                                                                       show_recently_used,
                                                                       catalog.getLocale( 1170 ), LABEL_LEFT, 0 ),
                                                     0, 1, AContainer::CO_INCWNR );

    AContainer *subcont0 = maincont->add( new AContainer( mainwin, 2, 1 ),
                                          0, 2 );
    subcont0->setMinSpace( 5 );
    subcont0->setMaxSpace( 5 );
    subcont0->setBorderWidth( 0 );

    subcont0->add( new Text( m_aguix, 0, 0, catalog.getLocale( 1008 ) ),
                   0, 0, AContainer::CO_FIX );
    m_breadcrumb = (Text*)subcont0->add( new Text( m_aguix, 0, 0, "" ),
                                         1, 0, AContainer::CO_INCW );

    AContainer *subcont1 = maincont->add( new AContainer( mainwin, 3, 2 ),
                                          0, 4 );
    subcont1->setMinSpace( 5 );
    subcont1->setMaxSpace( 5 );
    subcont1->setBorderWidth( 0 );

    subcont1->add( new Text( m_aguix, 0, 0, catalog.getLocale( 1009 ) ),
                   0, 0, AContainer::CO_INCW );
    m_lv = (FieldListView*)subcont1->add( new FieldListView( m_aguix, 0, 0, 200, 200,
                                                             0 ),
                                          0, 1, AContainer::CO_MIN );

    m_lv->setHBarState( 2 );
    m_lv->setVBarState( 2 );

    subcont1->add( new Text( m_aguix, 0, 0, catalog.getLocale( 1010 ) ),
                   1, 0, AContainer::CO_INCW );
    m_lv_help = (FieldListView*)subcont1->add( new FieldListView( m_aguix, 0, 0, 200, 200,
                                                                  0 ),
                                               1, 1, AContainer::CO_MIN );

    m_lv_help->setHBarState( 2 );
    m_lv_help->setVBarState( 2 );

    subcont1->add( new Text( m_aguix, 0, 0, catalog.getLocale( 1014 ) ),
                   2, 0, AContainer::CO_INCW );
    m_lv_key = (FieldListView*)subcont1->add( new FieldListView( m_aguix, 0, 0, 100, 200,
                                                                 0 ),
                                              2, 1, AContainer::CO_MIN );

    m_lv_key->setHBarState( 2 );
    m_lv_key->setVBarState( 2 );

    AContainer *subcont3 = maincont->add( new AContainer( mainwin, 2, 1 ),
                                          0, 3 );
    subcont3->setMinSpace( 5 );
    subcont3->setMaxSpace( 5 );
    subcont3->setBorderWidth( 0 );

    subcont3->add( new Text( m_aguix, 0, 0, catalog.getLocale( 793 ) ),
                   0, 0, AContainer::CO_FIX );
    Text *filtertext = (Text*)subcont3->add( new Text( m_aguix, 0, 0,
                                                       "" ),
                                         1, 0, AContainer::CO_INCW );

    AContainer *subcont2 = maincont->add( new AContainer( mainwin, 2, 1 ), 0, 5 );
    subcont2->setMinSpace( 5 );
    subcont2->setMaxSpace( -1 );
    subcont2->setBorderWidth( 0 );

    Button *okb = (Button*)subcont2->add( new Button( m_aguix,
                                                      0,
                                                      0,
                                                      catalog.getLocale( 392 ),
                                                      0 ), 0, 0, AContainer::CO_FIX );
    Button *cancelb = (Button*)subcont2->add( new Button( m_aguix,
                                                          0,
                                                          0,
                                                          catalog.getLocale( 8 ),
                                                          0 ), 1, 0, AContainer::CO_FIX );

    mainwin->contMaximize( true );

    help_tv->redraw();
    help_tv->maximizeYLines( 10 );
    maincont->readLimits();
    mainwin->contMaximize( true );

    int tw = Worker::getPersKVPStore().getIntValue( "commandmenu-width",
                                                    mainwin->getWidth(),
                                                    10000 );
    int th = Worker::getPersKVPStore().getIntValue( "commandmenu-height",
                                                    mainwin->getHeight(),
                                                    10000 );
    mainwin->resize( tw, th );

    mainwin->show();

    AGMessage *agmsg;

    MenuTreeNode *root = m_menu->getRootNode();

    if ( initial_node ) {
        auto node = findNode( root, initial_node );
        if ( node ) {
            m_menu->setCurrentNode( node );
        } else {
            m_menu->setCurrentNode( root );
        }
    } else {
        m_menu->setCurrentNode( root );
    }

    m_show_recently_used = show_recently_used;

    if ( show_recently_used ) {
        m_menu->setVisibleList( m_recently_used );
    } else {
        m_menu->setVisibleList( NULL );
    }
    
    m_menu->setFilter( "" );

    showMenu();
    updateBreadcrumb();

    std::string current_filter;

    MenuTreeNode *activate_element = NULL;

    int end_mode = 0;

    for ( ; end_mode == 0; ) {
        agmsg = m_aguix->WaitMessage( NULL );

        if ( agmsg ) {
            switch ( agmsg->type ) {
                case AG_CLOSEWINDOW:
                    end_mode = -1;
                    break;
                case AG_BUTTONCLICKED:
                    if ( agmsg->button.button == okb ) {
                        end_mode = 1;
                    } else if ( agmsg->button.button == cancelb ) {
                        end_mode = -1;
                    }
                    break;
                case AG_KEYPRESSED:
                    if ( agmsg->key.key == XK_BackSpace ) {
                        if ( KEYSTATEMASK( agmsg->key.keystate ) == ShiftMask ||
                             current_filter.empty() ) {
                            if ( m_menu->getCurrentNode()->getParent() != NULL ) {
                                const MenuTreeNode *old_entry = m_menu->getCurrentNode();

                                m_menu->setCurrentNode( m_menu->getCurrentNode()->getParent() );

                                m_menu->setFilter( filtertext->getText() );

                                showMenu();

                                highlightEntry( old_entry );

                                updateBreadcrumb();
                            }
                        } else {
                            std::string last_filter = current_filter;
                          
                            if ( last_filter.length() > 0 ) {
                                int prev_char = last_filter.length();
                                UTF8::movePosToPrevChar( last_filter.c_str(), prev_char );

                                if ( prev_char < 0 ) prev_char = 0;

                                last_filter.resize( prev_char );
                                current_filter = last_filter;

                                filtertext->setText( current_filter.c_str() );

                                m_menu->setFilter( filtertext->getText() );

                                showMenu();
                            }
                        }
                    } else if ( agmsg->key.key == XK_Return ) {
                        end_mode = 1;
                    } else if ( agmsg->key.key == XK_Up ) {
                        int row = m_lv->getActiveRow();
                        if ( row > 0 ) {
                            m_lv->setActiveRow( row - 1 );
                        }
                        m_lv->showActive();
                        m_lv->redraw();
                    } else if ( agmsg->key.key == XK_Down ) {
                        int row = m_lv->getActiveRow() + 1;

                        if ( row >= m_lv->getElements() ) {
                            row = m_lv->getElements() - 1;
                        }

                        m_lv->setActiveRow( row );
                        m_lv->showActive();
                        m_lv->redraw();
                    } else if ( agmsg->key.key == XK_Next ) {
                        int row = m_lv->getActiveRow();

                        row += m_lv->getMaxDisplayV();

                        if ( row >= m_lv->getElements() ) {
                            row = m_lv->getElements() - 1;
                        }

                        m_lv->setActiveRow( row );
                        m_lv->showActive();
                        m_lv->redraw();
                    } else if ( agmsg->key.key == XK_Prior ) {
                        int row = m_lv->getActiveRow();

                        row -= m_lv->getMaxDisplayV();

                        if ( row < 0 ) {
                            row = 0;
                        }

                        m_lv->setActiveRow( row );
                        m_lv->showActive();
                        m_lv->redraw();
                    } else if ( agmsg->key.key == XK_Home ) {
                        m_lv->setActiveRow( 0 );
                        m_lv->showActive();
                        m_lv->redraw();
                    } else if ( agmsg->key.key == XK_End ) {
                        int row;

                        row = m_lv->getElements() - 1;

                        m_lv->setActiveRow( row );
                        m_lv->showActive();
                        m_lv->redraw();
                    } else if ( agmsg->key.key == XK_Left ) {
                        if ( m_menu->getCurrentNode()->getParent() != NULL ) {
                            const MenuTreeNode *old_entry = m_menu->getCurrentNode();

                            m_menu->setCurrentNode( m_menu->getCurrentNode()->getParent() );

                            m_menu->setFilter( filtertext->getText() );

                            showMenu();

                            highlightEntry( old_entry );

                            updateBreadcrumb();
                        }
                    } else if ( agmsg->key.key == XK_slash ||
                                agmsg->key.key == XK_Right ) {
                        int row = m_lv->getActiveRow();

                        if ( m_lv->isValidRow( row ) ) {
                            std::string entry = m_lv->getText( row, 0 );

                            for ( const auto &it : *m_menu->getCurrentNode() ) {
                                if ( AGUIXUtils::starts_with( entry, it->getName() ) ) {
                                    if ( it->hasChildren() ) {
                                        current_filter = "";
                                        filtertext->setText( "" );

                                        m_menu->setCurrentNode( it );

                                        m_menu->setFilter( "" );

                                        showMenu();
                                        
                                        updateBreadcrumb();
                                    }
                                    break;
                                }
                            }
                        }
                    } else if ( agmsg->key.key == XK_Escape ) {
                        end_mode = -1;
                    } else if ( agmsg->key.key == XK_r &&
                                KEYSTATEMASK( agmsg->key.keystate ) == ControlMask ) {
                        if ( recently_cb->getState() ) {
                            m_menu->setVisibleList( NULL );
                            recently_cb->setState( false );
                            m_show_recently_used = false;
                        } else {
                            m_menu->setVisibleList( m_recently_used );
                            recently_cb->setState( true );
                            m_show_recently_used = true;
                        }

                        m_menu->setFilter( filtertext->getText() );

                        showMenu();

                        updateBreadcrumb();
                    } else if ( IsModifierKey( agmsg->key.key ) ||
                                IsCursorKey( agmsg->key.key ) ||
                                IsPFKey( agmsg->key.key ) ||
                                IsFunctionKey( agmsg->key.key ) ||
                                IsMiscFunctionKey( agmsg->key.key ) ||
                                ( ( agmsg->key.key >= XK_BackSpace ) && ( agmsg->key.key <= XK_Escape ) ) ) {
                    } else if ( strlen( agmsg->key.keybuf ) > 0 ) {
                        std::string last_filter = current_filter;
                        current_filter += agmsg->key.keybuf;

                        if ( m_menu->setFilter( current_filter ) < 1 ) {
                            // no match, revert filter
                            current_filter = last_filter;

                            m_menu->setFilter( current_filter );
                        } else {
                            filtertext->setText( current_filter.c_str() );

                            showMenu();

                            if ( ! current_filter.empty() ) {
                                std::string prefix;

                                if ( m_menu->getCurrentNode()->getParent() != NULL ) {
                                    prefix = m_menu->createPath( "/" );
                                }

                                std::string filter = prefix;

                                if ( ! filter.empty() ) {
                                    filter += "/";
                                }
                                filter += current_filter;

                                time_t t1;
                                std::string best_hit = m_pdb->getBestHit( filter, t1 );

                                for ( int row = 0; row < m_lv->getElements(); row++ ) {
                                    std::string fullname = prefix;
                                    if ( ! fullname.empty() ) {
                                        fullname += "/";
                                    }
                                    fullname += m_lv->getText( row, 0 );

                                    std::string fullname_with_help = fullname;
                                    fullname += ";";
                                    fullname += m_lv_help->getText( row, 0 );;

                                    if ( best_hit == fullname ||
                                         best_hit == fullname_with_help ) {
                                        m_lv->setActiveRow( row );
                                        m_lv->redraw();
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    syncHelpLV();
                    break;
                case AG_FIELDLV_ONESELECT:
                case AG_FIELDLV_MULTISELECT:
                case AG_FIELDLV_ENTRY_PRESSED:
                case AG_FIELDLV_VSCROLL:
                case AG_FIELDLV_HSCROLL:
                    syncHelpLV( agmsg->fieldlv.lv );
                    break;
                case AG_CHOOSECLICKED:
                    if ( agmsg->choose.button == recently_cb ) {
                        if ( agmsg->choose.state == true ) {
                            m_menu->setVisibleList( m_recently_used );
                            m_show_recently_used = true;
                        } else {
                            m_menu->setVisibleList( NULL );
                            m_show_recently_used = false;
                        }

                        m_menu->setFilter( filtertext->getText() );

                        showMenu();

                        updateBreadcrumb();
                    }
                    break;
            }

            m_aguix->ReplyMessage( agmsg );

            triggerEntryHighlightFunction( m_lv->getActiveRow() );
        }
    }

    triggerEntryHighlightFunction( nullptr );

    if ( end_mode == 1 ) {
        std::string prefix;

        if ( m_menu->getCurrentNode()->getParent() != NULL ) {
            prefix = m_menu->createPath( "/" );
        }

        std::string filter = prefix;

        int row = m_lv->getActiveRow();

        if ( m_lv->isValidRow( row ) ) {
            std::string fullname = prefix;
            if ( ! fullname.empty() ) {
                fullname += "/";
            }
            fullname += m_lv->getText( row, 0 );

            m_recently_used->removeEntry( fullname );
            m_recently_used->pushFrontEntry( fullname );

            if ( ! current_filter.empty() ) {

                fullname += ";";

                fullname += m_lv_help->getText( row, 0 );

                if ( ! filter.empty() ) {
                    filter += "/";
                }
                filter += current_filter;
                m_pdb->pushAccess( filter,
                                   fullname,
                                   0 );
            }

            int pos = 0;
            for ( const auto &it : m_current_entries ) {
                if ( pos == row ) {
                    activate_element = std::get< 1 >( it );
                    break;
                }
                pos++;
            }
        }
    }

    Worker::getPersKVPStore().setIntValue( "commandmenu-width",
                                           mainwin->getWidth() );
    Worker::getPersKVPStore().setIntValue( "commandmenu-height",
                                           mainwin->getHeight() );

    delete mainwin;

    if ( activate_element &&
         activate_element->getActivateFunction() ) {
        activate_element->getActivateFunction()();
    }
}

void MenuTreeUI::showMenu()
{
    std::string old_entry = m_lv->getText( m_lv->getActiveRow(), 0 );

    m_lv->setSize( 0 );
    m_lv_help->setSize( 0 );
    m_lv_key->setSize( 0 );

    m_current_entries.clear();

    m_menu->fillFullname( m_current_entries );

    if ( m_show_recently_used ) {
        m_current_entries.sort( []( const std::pair< std::string, MenuTreeNode * > &lhs,
                                    const std::pair< std::string, MenuTreeNode * > &rhs ) -> bool {
                                    int lhs_pos = lhs.second->getVisiblePos();
                                    int rhs_pos = rhs.second->getVisiblePos();

                                    if ( lhs_pos == rhs_pos ) {
                                        return lhs.second->getName() < rhs.second->getName ();
                                    }

                                    // put negative pos (not in visible list) last, should actually not happen

                                    if ( lhs_pos < 0 && rhs_pos >= 0 ) {
                                        return false;
                                    }

                                    if ( lhs_pos >= 0 && rhs_pos < 0 ) {
                                        return true;
                                    }

                                    return lhs_pos < rhs_pos;
                                } );
    }
    
    for ( const auto &it1 : m_current_entries ) {
        int row1 = m_lv->addRow();
        m_lv_help->addRow();
        m_lv_key->addRow();

        m_lv->setPreColors( row1, FieldListView::PRECOLOR_ONLYACTIVE );
        m_lv_help->setPreColors( row1, FieldListView::PRECOLOR_ONLYACTIVE );
        m_lv_key->setPreColors( row1, FieldListView::PRECOLOR_ONLYACTIVE );

        m_lv->setText( row1, 0, std::get< 0 >( it1 ) );
        m_lv_help->setText( row1, 0, std::get< 1 >( it1 )->getHelp() );
        m_lv_key->setText( row1, 0, std::get< 1 >( it1 )->getKey() );

        if ( std::get< 0 >( it1 ) == old_entry ) {
            m_lv->setActiveRow( row1 );
        }
    }

    if ( ! m_lv->isValidRow( m_lv->getActiveRow() ) ) {
        m_lv->setActiveRow( 0 );
    }

    m_lv->redraw();

    syncHelpLV();
}

void MenuTreeUI::updateBreadcrumb()
{
    if ( m_menu->getCurrentNode() == m_menu->getRootNode() ) {
        m_breadcrumb->setText( "" );
    } else {
        m_breadcrumb->setText( m_menu->createPath( " -> " ).c_str() );
    }
}

void MenuTreeUI::highlightEntry( const MenuTreeNode *entry )
{
    if ( ! m_lv || ! entry ) return;

    int row = 0;

    for ( const auto &it1 : m_current_entries ) {

        if ( std::get< 1 >( it1 ) == entry ) {
            m_lv->setActiveRow( row );
            break;
        }

        row++;
    }
}

void MenuTreeUI::syncHelpLV( FieldListView *source_lv )
{
    if ( source_lv == m_lv || source_lv == NULL ) {
        m_lv_help->setYOffset( m_lv->getYOffset() );
        m_lv_help->setActiveRow( m_lv->getActiveRow() );
        m_lv_help->redraw();
        m_lv_key->setYOffset( m_lv->getYOffset() );
        m_lv_key->setActiveRow( m_lv->getActiveRow() );
        m_lv_key->redraw();
    } else if ( source_lv == m_lv_help ) {
        m_lv->setYOffset( m_lv_help->getYOffset() );
        m_lv->setActiveRow( m_lv_help->getActiveRow() );
        m_lv->redraw();
        m_lv_key->setYOffset( m_lv_help->getYOffset() );
        m_lv_key->setActiveRow( m_lv_help->getActiveRow() );
        m_lv_key->redraw();
    } else if ( source_lv == m_lv_key ) {
        m_lv->setYOffset( m_lv_key->getYOffset() );
        m_lv->setActiveRow( m_lv_key->getActiveRow() );
        m_lv->redraw();
        m_lv_help->setYOffset( m_lv_key->getYOffset() );
        m_lv_help->setActiveRow( m_lv_key->getActiveRow() );
        m_lv_help->redraw();
    }
}

void MenuTreeUI::callDeHighlightFunction( MenuTreeNode *new_entry, MenuTreeNode *old_entry )
{
    if ( old_entry == NULL ) return;

    while ( new_entry != NULL && new_entry->getDepth() > old_entry->getDepth () ) {
        new_entry = new_entry->getParent();
    }

    // abort if both entries are the same
    if ( new_entry == old_entry ) return;

    if ( old_entry->getDeHighlightFunction() ) {
        old_entry->getDeHighlightFunction()();
    }

    if ( new_entry != NULL ) {
        if ( old_entry->getDepth() > new_entry->getDepth() ) {
            callDeHighlightFunction( new_entry,
                                     old_entry->getParent() );
        } else {
            callDeHighlightFunction( new_entry->getParent(),
                                     old_entry->getParent() );
        }
    } else {
        callDeHighlightFunction( NULL,
                                 old_entry->getParent() );
    }
}

void MenuTreeUI::callHighlightFunction( MenuTreeNode *new_entry, MenuTreeNode *old_entry )
{
    if ( new_entry == NULL ) return;

    while ( old_entry != NULL && old_entry->getDepth() > new_entry->getDepth () ) {
        old_entry = old_entry->getParent();
    }

    // abort if both entries are the same
    if ( new_entry == old_entry ) return;

    if ( old_entry != NULL ) {
        if ( new_entry->getDepth() > old_entry->getDepth() ) {
            callHighlightFunction( new_entry->getParent(),
                                   old_entry );
        } else {
            callHighlightFunction( new_entry->getParent(),
                                   old_entry->getParent() );
        }
    } else {
        callHighlightFunction( new_entry->getParent(),
                               NULL );
    }

    if ( new_entry->getHighlightFunction() ) {
        new_entry->getHighlightFunction()();
    }
}

void MenuTreeUI::triggerEntryHighlightFunction( MenuTreeNode *entry )
{
    callDeHighlightFunction( entry, m_current_dehighlight_entry );

    if ( entry ) {
        callHighlightFunction( entry, m_current_dehighlight_entry );
    }

    m_current_dehighlight_entry = entry;
}

void MenuTreeUI::triggerEntryHighlightFunction( int row )
{
    int pos = 0;
    for ( const auto &it : m_current_entries ) {
        if ( pos == row ) {
            triggerEntryHighlightFunction( std::get< 1 >( it ) );
            break;
        }
        pos++;
    }
}
