flu_tree_browser.cpp
来自「ncbi源码」· C++ 代码 · 共 2,583 行 · 第 1/5 页
CPP
2,583 行
void Flu_Tree_Browser :: Node :: print( int spaces ){ for( int s = 0; s < spaces; s++ ) printf( " " ); if( is_leaf() ) printf( " %s\n", text.c_str() ); else printf( "[%s]\n", text.c_str() ); for( int i = 0; i < _children.size(); i++ ) _children.child(i)->print( spaces+2 );}void Flu_Tree_Browser :: draw(){ if( rdata.forceResize ) { resize( x(), y(), w(), h() ); rdata.forceResize = false; } // draw the background color fl_draw_box( FL_FLAT_BOX, _box->x(), _box->y(), _box->w(), _box->h(), _box->color() ); int dx = Fl::box_dx(box()), dy = Fl::box_dy(box()); // set up the recursive data structure rdata.x = x()+dx; rdata.y = y()+dy; // account for the positions of the scrollbars if( scrollH->visible() ) rdata.x -= scrollH->value(); if( scrollV->visible() ) rdata.y -= scrollV->value(); rdata.first = true; rdata.last = true; rdata.bgColor = _box->color(); rdata.shadedIndex = 0; // pick the connector line and selection colors depending on the active state if( active() ) { rdata.lineColor = rdata.defLineColor; rdata.selectionColor = rdata.defSelectionColor; } else { rdata.lineColor = fl_inactive( rdata.defLineColor ); rdata.selectionColor = fl_inactive( rdata.defSelectionColor ); } // draw the tree fl_push_clip( _box->x(), _box->y(), _box->w(), _box->h() ); root.recurse( rdata, Node::DRAW ); // if dragging to move, draw a bar showing where the dragged node will be inserted#ifdef USE_FLU_DND if( dnd_is_dragging() && rdata.isMoveValid && rdata.dragging ) { bool drawLine = false; if( dnd_event_is_text() ) drawLine = true; else if( dnd_is_data_type( "Flu_Tree_Browser" ) ) { if( !rdata.moveOnlySameGroup || ( rdata.grabbed->parent() == rdata.dragNode->parent() ) ) drawLine = true; } else if( dnd_is_data_type( "DND_Object" ) ) drawLine = true; if( drawLine && rdata.dragWhere != MOVE_INSIDE ) { fl_color( FL_RED ); fl_line_style( FL_SOLID, 2 ); fl_line( _box->x(), rdata.dragPos, _box->x()+_box->w(), rdata.dragPos ); fl_line_style( 0 ); } }#endif fl_pop_clip(); // draw the kids draw_child( *scrollBox ); draw_child( *scrollH ); draw_child( *scrollV ); // draw the box last so it's on top fl_draw_box( _box->box(), _box->x(), _box->y(), _box->w(), _box->h(), _box->color() );}inline void draw_T( int x, int y, int w, int h ){ int w2 = w >> 1; int h2 = h >> 1; fl_line( x+w2, y, x+w2, y+h ); fl_line( x+w2, y+h2, x+w, y+h2 );}inline void draw_L( int x, int y, int w, int h ){ int w2 = w >> 1; int h2 = h >> 1; fl_line( x+w2, y, x+w2, y+h2 ); fl_line( x+w2, y+h2, x+w, y+h2 );}inline void draw_Lflip( int x, int y, int w, int h ){ int w2 = w >> 1; int h2 = h >> 1; fl_line( x+w2, y+h, x+w2, y+h2 ); fl_line( x+w2, y+h2, x, y+h2 );}inline void draw_Ldash( int x, int y, int w, int h ){ w = w >> 1; h = h >> 1; fl_line( x, y+h, x+w, y+h );}inline void draw_vert_dash( int x, int y, int w, int h ){ w = w >> 1; fl_line( x+w, y+(h>>1), x+w, y+h );}inline void draw_Rdash( int x, int y, int w, int h ){ h = h >> 1; fl_line( x+w, y+h, x+(w>>1), y+h );}void Flu_Tree_Browser :: Node :: draw( RData &rdata, bool measure ){ int which = open(); // i.e. which icon: open or closed? bool skipCollapser = is_root() && rdata.showRoot && ( CHECK(ALWAYS_OPEN) || rdata.allBranchesAlwaysOpen ); int halfHGap = rdata.hGap >> 1, halfVGap = rdata.vGap >> 1; bool doDraw = !measure; int X = rdata.x; int Y = rdata.y; Fl_Color bgColor = rdata.shadedColors[rdata.shadedIndex], tColor = textColor, hilightColor = rdata.selectionColor; // pick the text color depending on the active state if( !rdata.tree->active() || !CHECK(ACTIVE)) tColor = fl_inactive( tColor ); if( doDraw ) { // draw the background for the entry using the entry background color fl_draw_box( FL_FLAT_BOX, rdata.browserX, Y, rdata.browserW, currentH, bgColor ); // if dragging to the inside of a branch, hilight that branch#ifdef USE_FLU_DND if( tree->dnd_is_dragging() && rdata.isMoveValid && rdata.dragWhere == MOVE_INSIDE && rdata.dragNode == this ) { bgColor = FL_RED; tColor = fl_contrast( tColor, bgColor ); hilightColor = rdata.bgColor; fl_draw_box( FL_FLAT_BOX, rdata.browserX, Y, rdata.browserW, currentH, bgColor ); } // if selected, draw a filled selection box and reverse the normal draw colors else if( CHECK(SELECTED) )#else if( CHECK(SELECTED) )#endif { bgColor = rdata.selectionColor; tColor = fl_contrast( tColor, bgColor ); hilightColor = rdata.bgColor; fl_draw_box( FL_FLAT_BOX, rdata.browserX, Y, rdata.browserW, currentH, bgColor ); } fl_color( rdata.lineColor ); fl_line_style( rdata.lineStyle, rdata.lineWidth ); } if( is_leaf() ) // draw leaves one way... { // draw the connectors if( doDraw && rdata.showConnectors && rdata.showBranches ) { if( rdata.last ) draw_L( X-halfHGap, Y-halfVGap, rdata.branchIconW+rdata.hGap, currentH+rdata.vGap ); else draw_T( X-halfHGap, Y-halfVGap, rdata.branchIconW+rdata.hGap, currentH+rdata.vGap ); } // account for leaf icon spacing if( rdata.showBranches ) { if( lIcon ) X += rdata.collapseIcons[which]->w() + rdata.hGap; else X += rdata.collapseIcons[which]->w() + rdata.wGap; } else X += rdata.wGap; // draw some more connectors if( doDraw && rdata.showConnectors && lIcon && rdata.showBranches ) draw_Ldash( X-halfHGap, Y-halfVGap, lIcon->w()+rdata.hGap, currentH+rdata.vGap ); // draw the leaf icon if( lIcon ) { if( doDraw ) lIcon->draw( X, Y+(currentH>>1)-(lIcon->h()>>1) ); X += lIcon->w() + rdata.wGap; } } else // ...and branches another { // force the root to the left if it has no visible children if( _parent == 0 && !CHECK(SOME_VISIBLE_CHILDREN) ) { skipCollapser = true; which = 0; } if( !CHECK(SOME_VISIBLE_CHILDREN) && !rdata.showLeaves ) which = 0; // draw the connectors if( doDraw && !skipCollapser && rdata.showConnectors && rdata.showBranches ) { if( _parent==0 ) { if( CHECK(SOME_VISIBLE_CHILDREN) ) draw_Rdash( X-halfHGap, Y-halfVGap, rdata.collapseIcons[which]->w()+4+rdata.hGap, currentH+rdata.vGap ); } else if( rdata.last ) draw_L( X-halfHGap, Y-halfVGap, rdata.branchIconW+rdata.hGap, currentH+rdata.vGap ); else draw_T( X-halfHGap, Y-halfVGap, rdata.branchIconW+rdata.hGap, currentH+rdata.vGap ); } // draw the collapsed icons if( doDraw && !skipCollapser && !CHECK(ALWAYS_OPEN) && !rdata.allBranchesAlwaysOpen ) { if( CHECK(SOME_VISIBLE_CHILDREN) || rdata.showLeaves ) { if( _parent==0 ) cIcon[which]->draw( X, Y+(currentH>>1)-(cIcon[which]->h()>>1) ); else cIcon[which]->draw( X+(rdata.branchIconW>>1)-(cIcon[which]->w()>>1), Y+(currentH>>1)-(cIcon[which]->h()>>1) ); } } if( !skipCollapser ) { X += cIcon[which]->w(); if( bIcon[which] ) X += rdata.hGap; else X += rdata.wGap; } // draw some more connectors if( doDraw && rdata.showConnectors && rdata.showBranches ) { int hGap = rdata.hGap; if( bIcon[which] ) hGap += bIcon[which]->w(); if( skipCollapser && CHECK(SOME_VISIBLE_CHILDREN) ) draw_vert_dash( X-halfHGap, Y-halfVGap, hGap, currentH+rdata.vGap ); else if( !which || !CHECK(SOME_VISIBLE_CHILDREN) ) draw_Ldash( X-halfHGap, Y-halfVGap, hGap, currentH+rdata.vGap ); else draw_Lflip( X-halfHGap, Y-halfVGap, hGap, currentH+rdata.vGap ); } // draw the branch icon if( bIcon[which] ) { if( doDraw ) bIcon[which]->draw( X, Y+(currentH>>1)-(bIcon[which]->h()>>1) ); X += bIcon[which]->w() + rdata.wGap; } } if( doDraw ) fl_line_style( 0 ); // draw the entry if( CHECK(SHOW_LABEL) ) { if( doDraw ) { fl_draw_box( FL_FLAT_BOX, X, Y+(currentH>>1)-(textH>>1), textW, textH, bgColor ); fl_color( tColor ); fl_font( textFont, textSize ); fl_draw( text.c_str(), X, Y+(currentH>>1)-(textH>>1), textW, textH, FL_ALIGN_LEFT ); } X += textW; } if( _widget ) { int widgetW = _widget->w->w(); int widgetH = _widget->w->h(); if( doDraw ) { _widget->w->redraw(); _widget->w->position( X, Y+(currentH>>1)-(widgetH>>1) ); if( CHECK(EXPAND_TO_WIDTH) ) _widget->w->size( MAX( _widget->defaultW, rdata.browserW - (X-rdata.browserX) ), _widget->w->h() ); _widget->w->draw(); } if( CHECK(EXPAND_TO_WIDTH) ) { if( _widget->w->w() == _widget->defaultW ) X += _widget->defaultW; } else X += widgetW; } // if hilighted, draw a box outlining the entry if( rdata.hilighted == this && doDraw ) { fl_color( hilightColor ); fl_line_style( FL_DOT, 1 ); fl_rect( rdata.browserX, Y, rdata.browserW, currentH, hilightColor ); fl_line_style( 0 ); } rdata.totalW = MAX( rdata.totalW, X );}void Flu_Tree_Browser :: Node :: select( bool b ){ if( (CHECK(SELECTED)==b) && (tree->rdata.when != FL_WHEN_NOT_CHANGED) ) return; SET(SELECTED,b); tree->redraw(); if( tree->rdata.when == FL_WHEN_RELEASE ) return; if( b ) do_callback( FLU_SELECTED ); else do_callback( FLU_UNSELECTED );}void Flu_Tree_Browser :: timerScrollCB(){ bool doRedraw = false; float val = scrollV->value() + autoScrollY; if( val < 0.0f ) val = 0.0f; if( val > scrollV->maximum() ) val = scrollV->maximum(); doRedraw |= ( val != scrollV->value() ); ((Fl_Valuator*)scrollV)->value( val ); val = scrollH->value() + autoScrollX; if( val < 0.0f ) val = 0.0f; if( val > scrollH->maximum() ) val = scrollH->maximum(); doRedraw |= ( val != scrollH->value() ); ((Fl_Valuator*)scrollH)->value( val ); Fl::repeat_timeout( 0.02, _timerScrollCB, this ); scrolledTimerOn = true; if( doRedraw ) redraw();}void Flu_Tree_Browser :: timerRedrawCB(){ if( rdata.animating ) Fl::repeat_timeout( 1.0f/rdata.fps, _timerRedrawCB, this ); redraw();}void Flu_Tree_Browser :: Node :: open( bool b ){ if( is_leaf() ) return; if( CHECK(ALWAYS_OPEN) || tree->rdata.allBranchesAlwaysOpen ) return; if( (open() == b) && (tree->rdata.when != FL_WHEN_NOT_CHANGED) ) return; tree->rdata.justOpenedClosed = true; SET(COLLAPSED,!b); if( tree->rdata.animate ) { // if we aren't yet animating a node, animate it! if( !tree->rdata.animating && !tree->rdata.animatedNode ) { // if we don't know how high all the children are, find out // (this only happens once per node, the first time it is opened) if( totalChildH == 0 ) { RData r = tree->rdata; r.x = r.y = r.totalW = 0; recurse( r, Node::MEASURE_THIS_OPEN ); } // set the initial offset based on whether the branch is open or closed tree->rdata.animationOffset = b ? -totalChildH : -1; // the delta is how much to change the offset each frame tree->rdata.animationDelta = totalChildH / ( tree->rdata.collapseTime * tree->rdata.fps ); tree->rdata.animationDelta = b ? tree->rdata.animationDelta : -tree->rdata.animationDelta; tree->rdata.animating = true; tree->rdata.animatedNode = this; Fl::add_timeout( 1.0f/tree->rdata.fps, _timerRedrawCB, tree ); } // otherwise reverse the direction of the animation, only if we are animating this node else if( tree->rdata.animating && tree->rdata.animatedNode==this ) { if( b ^ (tree->rdata.animationDelta>0) ) tree->rdata.animationDelta = -tree->rdata.animationDelta; } } if( open() && (_parent != 0) ) // root node doesn't count as a single open branch { if( ( tree->rdata.lastOpenBranch != this ) && tree->rdata.singleBranchOpen ) tree->rdata.lastOpenBranch->close(); tree->rdata.lastOpenBranch = this; } tree->rdata.forceResize = true; tree->rdata.visibilityChanged = true; if( b ) do_callback( FLU_OPENED ); else do_callback( FLU_CLOSED );}void Flu_Tree_Browser :: Node :: active( bool b ){ if( CHECK(ACTIVE) == b && tree->rdata.when != FL_WHEN_NOT_CHANGED ) return; SET( ACTIVE, b ); if( _widget ) { if( b ) _widget->w->activate(); else _widget->w->deactivate(); } if( !CHECK(ACTIVE) ) { if( tree->rdata.hilighted == this ) tree->set_hilighted( NULL ); select( false ); open( false ); }}void Flu_Tree_Browser :: Node :: unselect_all( Node* except ){ if( this != except ) select( false ); for( int i = 0; i < _children.size(); i++ ) _children.child(i)->unselect_all( except );}void Flu_Tree_Browser :: Node :: select_all(){ select( true ); for( int i = 0; i < _children.size(); i++ ) _children.child(i)->select_all();}bool Flu_Tree_Browser :: Node :: isMoveValid( Node* &n1, int &where, Node* &n2 ){ // if n1 is NULL, then check it as if it were a node being moved from another tree if( n2 == NULL ) return false; // check the validity of the move: // 1) the source and destination nodes can't be the same // 2) you can't move before the root node // 3) you can't move an unmovable node or move a branch node such that it would become a descendent of itself // 4) if moving only within the same group, check that the parents are the same // 5) if moving into a sorted tree, the destination node MUST be a branch // 6) a move AFTER an OPEN branch is a move BEFORE its first child // 7) you can't move a node into a non-droppable branch node if( n1 == n2 ) return false; if( where==MOVE_BEFORE && n2->is_root() ) return false; if( n1 ) { if( !n1->movable() ) return false; if( n1->is_branch() ) if( n1->is_descendent( n2 ) ) return false; } bool sameGroup = n2->tree->move_only_same_group(); if( sameGroup && n1 ) { if( n1->parent() != n2->parent() || where==MOVE_INSIDE ) return false; } int iMode = n2->tree->insertion_mode(); if( iMode == FLU_INSERT_SORTED || iMode == FLU_INSERT_SORTED_REVERSE ) { if( n2->is_branch() ) { where = MOVE_INSIDE;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?