📄 ctrl_tree.cpp
字号:
/***************************************************************************** * ctrl_tree.cpp ***************************************************************************** * Copyright (C) 2003 VideoLAN * $Id: ctrl_tree.cpp 16457 2006-08-31 20:51:12Z hartman $ * * Authors: Antoine Cellerier <dionoea@videolan.org> * * 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 Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/#include <math.h>#include "../utils/var_bool.hpp"#include "ctrl_tree.hpp"#include "../src/os_factory.hpp"#include "../src/os_graphics.hpp"#include "../src/generic_bitmap.hpp"#include "../src/generic_font.hpp"#include "../src/scaled_bitmap.hpp"#include "../utils/position.hpp"#include "../utils/ustring.hpp"#include "../events/evt_key.hpp"#include "../events/evt_mouse.hpp"#include "../events/evt_scroll.hpp"#include "vlc_keys.h"#ifdef sun# include "solaris_specific.h" // for lrint#endif#define SCROLL_STEP 0.05#define LINE_INTERVAL 1 // Number of pixels inserted between 2 linesCtrlTree::CtrlTree( intf_thread_t *pIntf, VarTree &rTree, const GenericFont &rFont, const GenericBitmap *pBgBitmap, const GenericBitmap *pItemBitmap, const GenericBitmap *pOpenBitmap, const GenericBitmap *pClosedBitmap, uint32_t fgColor, uint32_t playColor, uint32_t bgColor1, uint32_t bgColor2, uint32_t selColor, const UString &rHelp, VarBool *pVisible, VarBool *pFlat ): CtrlGeneric( pIntf,rHelp, pVisible), m_rTree( rTree), m_rFont( rFont ), m_pBgBitmap( pBgBitmap ), m_pItemBitmap( pItemBitmap ), m_pOpenBitmap( pOpenBitmap ), m_pClosedBitmap( pClosedBitmap ), m_fgColor( fgColor ), m_playColor( playColor ), m_bgColor1( bgColor1 ), m_bgColor2( bgColor2 ), m_selColor( selColor ), m_pLastSelected( NULL ), m_pImage( NULL ), m_dontMove( false ){ // Observe the tree and position variables m_rTree.addObserver( this ); m_rTree.getPositionVar().addObserver( this ); m_flat = pFlat->get(); m_firstPos = m_flat ? m_rTree.firstLeaf() : m_rTree.begin(); makeImage();}CtrlTree::~CtrlTree(){ m_rTree.getPositionVar().delObserver( this ); m_rTree.delObserver( this ); if( m_pImage ) { delete m_pImage; }}int CtrlTree::itemHeight(){ int itemHeight = m_rFont.getSize(); if( !m_flat ) { if( m_pClosedBitmap ) { itemHeight = __MAX( m_pClosedBitmap->getHeight(), itemHeight ); } if( m_pOpenBitmap ) { itemHeight = __MAX( m_pOpenBitmap->getHeight(), itemHeight ); } } if( m_pItemBitmap ) { itemHeight = __MAX( m_pItemBitmap->getHeight(), itemHeight ); } itemHeight += LINE_INTERVAL; return itemHeight;}int CtrlTree::itemImageWidth(){ int bitmapWidth = 5; if( !m_flat ) { if( m_pClosedBitmap ) { bitmapWidth = __MAX( m_pClosedBitmap->getWidth(), bitmapWidth ); } if( m_pOpenBitmap ) { bitmapWidth = __MAX( m_pOpenBitmap->getWidth(), bitmapWidth ); } } if( m_pItemBitmap ) { bitmapWidth = __MAX( m_pItemBitmap->getWidth(), bitmapWidth ); } return bitmapWidth + 2;}int CtrlTree::maxItems(){ const Position *pPos = getPosition(); if( !pPos ) { return -1; } return pPos->getHeight() / itemHeight();}void CtrlTree::onUpdate( Subject<VarTree, tree_update> &rTree, tree_update *arg ){ if( arg->i_type == 0 ) // Item update { if( arg->b_active_item ) { autoScroll(); ///\todo We should make image if we are visible in the view makeImage(); } } /// \todo handle delete in a more clever way else if ( arg->i_type == 1 ) // Global change or deletion { m_firstPos = m_flat ? m_rTree.firstLeaf() : m_rTree.begin(); makeImage(); } else if ( arg->i_type == 2 ) // Item-append { if( m_flat && m_firstPos->size() ) m_firstPos = m_rTree.getNextLeaf( m_firstPos ); /// \todo Check if the item is really visible in the view // (we only check if it in the document) if( arg->b_visible == true ) { makeImage(); } } else if( arg->i_type == 3 ) // item-del { /* Make sure firstPos and lastSelected are still valid */ while( m_firstPos->m_deleted && m_firstPos != m_rTree.root()->begin() ) { m_firstPos = m_flat ? m_rTree.getPrevLeaf( m_firstPos ) : m_rTree.getPrevVisibleItem( m_firstPos ); } if( m_firstPos->m_deleted ) m_firstPos = m_flat ? m_rTree.firstLeaf() : m_rTree.root()->begin(); if( arg->b_visible == true ) { makeImage(); } } notifyLayout();}void CtrlTree::onUpdate( Subject<VarPercent> &rPercent, void* arg){ // Determine what is the first item to display VarTree::Iterator it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin(); if( m_dontMove ) return; int excessItems; if( m_flat ) excessItems = m_rTree.countLeafs() - maxItems(); else excessItems = m_rTree.visibleItems() - maxItems(); if( excessItems > 0) { VarPercent &rVarPos = m_rTree.getPositionVar(); // a simple (int)(...) causes rounding errors !#ifdef _MSC_VER# define lrint (int)#endif if( m_flat ) it = m_rTree.getLeaf(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1 ); else it = m_rTree.getVisibleItem(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1 ); } if( m_firstPos != it ) { // Redraw the control if the position has changed m_firstPos = it; makeImage(); notifyLayout(); }}void CtrlTree::onResize(){ // Determine what is the first item to display VarTree::Iterator it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin(); int excessItems; if( m_flat ) excessItems = m_rTree.countLeafs() - maxItems(); else excessItems = m_rTree.visibleItems() - maxItems(); if( excessItems > 0) { VarPercent &rVarPos = m_rTree.getPositionVar(); // a simple (int)(...) causes rounding errors !#ifdef _MSC_VER# define lrint (int)#endif if( m_flat ) it = m_rTree.getLeaf(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1 ); else it = m_rTree.getVisibleItem(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1 ); } // Redraw the control if the position has changed m_firstPos = it; makeImage(); notifyLayout();}void CtrlTree::onPositionChange(){ makeImage(); notifyLayout();}void CtrlTree::handleEvent( EvtGeneric &rEvent ){ bool bChangedPosition = false; VarTree::Iterator toShow; bool needShow = false; if( rEvent.getAsString().find( "key:down" ) != string::npos ) { int key = ((EvtKey&)rEvent).getKey(); VarTree::Iterator it; bool previousWasSelected = false; /* Delete the selection */ if( key == KEY_DELETE ) { /* Find first non selected item before m_pLastSelected */ VarTree::Iterator it_sel = m_flat ? m_rTree.firstLeaf() : m_rTree.begin(); for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin(); it != m_rTree.end(); it = m_flat ? m_rTree.getNextLeaf( it ) : m_rTree.getNextVisibleItem( it ) ) { if( &*it == m_pLastSelected ) break; if( !it->m_selected ) it_sel = it; } /* Delete selected stuff */ m_rTree.delSelected(); /* Select it_sel */ it_sel->m_selected = true; m_pLastSelected = &*it_sel; } else if( key == KEY_PAGEDOWN ) { it = m_firstPos; int i = (int)(maxItems()*1.5); while( i >= 0 ) { VarTree::Iterator it_old = it; it = m_flat ? m_rTree.getNextLeaf( it ) : m_rTree.getNextVisibleItem( it ); /* End is already visible, dont' scroll */ if( it == m_rTree.end() ) { it = it_old; break; } needShow = true; i--; } if( needShow ) { ensureVisible( it ); makeImage(); notifyLayout(); return; } } else if (key == KEY_PAGEUP ) { it = m_firstPos; int i = maxItems(); while( i >= maxItems()/2 ) { it = m_flat ? m_rTree.getPrevLeaf( it ) : m_rTree.getPrevVisibleItem( it ); /* End is already visible, dont' scroll */ if( it == ( m_flat ? m_rTree.firstLeaf() : m_rTree.begin() ) ) { break; } i--; } ensureVisible( it ); makeImage(); notifyLayout(); return; } for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin(); it != m_rTree.end(); it = m_flat ? m_rTree.getNextLeaf( it ) : m_rTree.getNextVisibleItem( it ) ) { VarTree::Iterator next = m_flat ? m_rTree.getNextLeaf( it ) : m_rTree.getNextVisibleItem( it ); if( key == KEY_UP ) { // Scroll up one item if( ( it->parent() && it != it->parent()->begin() ) || &*it != m_pLastSelected ) { bool nextWasSelected = ( &*next == m_pLastSelected ); it->m_selected = nextWasSelected; if( nextWasSelected ) { m_pLastSelected = &*it; needShow = true; toShow = it; } } } else if( key == KEY_DOWN ) { // Scroll down one item if( ( it->parent() && next != it->parent()->end() ) || &*it != m_pLastSelected ) { (*it).m_selected = previousWasSelected; } if( previousWasSelected ) { m_pLastSelected = &*it; needShow = true; toShow = it; previousWasSelected = false; } else { previousWasSelected = ( &*it == m_pLastSelected ); } // Fix last tree item selection if( ( m_flat ? m_rTree.getNextLeaf( it ) : m_rTree.getNextVisibleItem( it ) ) == m_rTree.end() && &*it == m_pLastSelected ) { (*it).m_selected = true; } } else if( key == KEY_RIGHT ) { // Go down one level (and expand node) if( &*it == m_pLastSelected ) { if( it->m_expanded ) { if( it->size() ) { it->m_selected = false; it->begin()->m_selected = true; m_pLastSelected = &*(it->begin()); } else { m_rTree.action( &*it ); } } else { it->m_expanded = true; bChangedPosition = true; } } } else if( key == KEY_LEFT ) { // Go up one level (and close node) if( &*it == m_pLastSelected ) { if( it->m_expanded && it->size() ) { it->m_expanded = false; bChangedPosition = true; } else { if( it->parent() && it->parent() != &m_rTree) { it->m_selected = false; m_pLastSelected = it->parent(); m_pLastSelected->m_selected = true; } } } } else if( key == KEY_ENTER || key == KEY_SPACE ) { // Go up one level (and close node) if( &*it == m_pLastSelected )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -