From 4cdd8e754acce59a8cd0307d4e99e89c34feaca3 Mon Sep 17 00:00:00 2001 From: Henner Zeller Date: Tue, 18 Feb 2014 16:41:27 -0500 Subject: [PATCH] Eeschema component selection dialog improvements. * Allow to select units in components that have more than one right in the component chooser dialog. * Keep chosen unit in history. * Show preview of current component unit as thumbnail image next to the description box. * Fixes lp:1280567 --- eeschema/component_tree_search_container.cpp | 239 ++++++++------ eeschema/component_tree_search_container.h | 30 +- eeschema/dialogs/dialog_choose_component.cpp | 234 +++++++++----- eeschema/dialogs/dialog_choose_component.h | 23 +- .../dialogs/dialog_choose_component_base.cpp | 34 +- .../dialogs/dialog_choose_component_base.fbp | 297 ++++++------------ .../dialogs/dialog_choose_component_base.h | 8 +- eeschema/getpart.cpp | 18 +- eeschema/lib_arc.cpp | 12 +- eeschema/lib_circle.cpp | 9 +- eeschema/lib_polyline.cpp | 9 +- eeschema/lib_rectangle.cpp | 9 +- eeschema/libedit.cpp | 6 +- eeschema/onleftclick.cpp | 10 +- include/sch_base_frame.h | 15 +- include/wxEeschemaStruct.h | 8 +- 16 files changed, 493 insertions(+), 468 deletions(-) diff --git a/eeschema/component_tree_search_container.cpp b/eeschema/component_tree_search_container.cpp index f0d9a2ffb1..015397349d 100644 --- a/eeschema/component_tree_search_container.cpp +++ b/eeschema/component_tree_search_container.cpp @@ -44,14 +44,19 @@ static const unsigned kLowestDefaultScore = 1; struct COMPONENT_TREE_SEARCH_CONTAINER::TREE_NODE { - TREE_NODE(TREE_NODE* aParent, CMP_LIBRARY* aOwningLib, + // Levels of nodes. + enum NODE_TYPE { + TYPE_LIB, + TYPE_ALIAS, + TYPE_UNIT + }; + + TREE_NODE(NODE_TYPE aType, TREE_NODE* aParent, LIB_ALIAS* aAlias, const wxString& aName, const wxString& aDisplayInfo, - const wxString& aSearchText, - bool aNormallyExpanded = false) - : Parent( aParent ), - Lib( aOwningLib ), - NormallyExpanded( aNormallyExpanded ), - Name( aName ), + const wxString& aSearchText ) + : Type( aType ), + Parent( aParent ), Alias( aAlias ), Unit( 0 ), + DisplayName( aName ), DisplayInfo( aDisplayInfo ), MatchName( aName.Lower() ), SearchText( aSearchText.Lower() ), @@ -59,10 +64,11 @@ struct COMPONENT_TREE_SEARCH_CONTAINER::TREE_NODE { } - TREE_NODE* const Parent; ///< NULL if library, pointer to lib-node when component. - CMP_LIBRARY* const Lib; ///< Owning library of this component. - const bool NormallyExpanded; ///< If this is a parent node, should it be unfolded ? - const wxString Name; ///< Exact name as displayed to the user. + const NODE_TYPE Type; ///< Type of node in the hierarchy. + TREE_NODE* const Parent; ///< NULL if library, pointer to parent when component/alias. + LIB_ALIAS* const Alias; ///< Component alias associated with this entry. + int Unit; ///< Part number; Assigned: >= 1; default = 0 + const wxString DisplayName; ///< Exact name as displayed to the user. const wxString DisplayInfo; ///< Additional info displayed in the tree (description..) const wxString MatchName; ///< Preprocessed: lowercased display name. @@ -75,27 +81,25 @@ struct COMPONENT_TREE_SEARCH_CONTAINER::TREE_NODE // Sort tree nodes by reverse match-score (bigger is first), then alphabetically. -// Library nodes (i.e. the ones that don't have a parent) are always sorted before any -// leaf nodes. +// Library (i.e. the ones that don't have a parent) are always sorted before any +// leaf nodes. Component bool COMPONENT_TREE_SEARCH_CONTAINER::scoreComparator( const TREE_NODE* a1, const TREE_NODE* a2 ) { - if ( a1->Parent == NULL && a2->Parent != NULL ) - return true; + if( a1->Type != a2->Type ) + return a1->Type < a2->Type; - if ( a1->Parent != NULL && a2->Parent == NULL ) - return false; - - if ( a1->MatchScore != a2->MatchScore ) + if( a1->MatchScore != a2->MatchScore ) return a1->MatchScore > a2->MatchScore; // biggest first. - if (a1->Parent != a2->Parent) - return a1->Parent->MatchName.Cmp(a2->Parent->MatchName) < 0; + if( a1->Parent != a2->Parent ) + return scoreComparator( a1->Parent, a2->Parent ); return a1->MatchName.Cmp( a2->MatchName ) < 0; } + COMPONENT_TREE_SEARCH_CONTAINER::COMPONENT_TREE_SEARCH_CONTAINER() - : tree( NULL ) + : tree( NULL ), libraries_added( 0 ), preselect_unit_number( -1 ) { } @@ -108,9 +112,11 @@ COMPONENT_TREE_SEARCH_CONTAINER::~COMPONENT_TREE_SEARCH_CONTAINER() } -void COMPONENT_TREE_SEARCH_CONTAINER::SetPreselectNode( const wxString& aComponentName ) +void COMPONENT_TREE_SEARCH_CONTAINER::SetPreselectNode( const wxString& aComponentName, + int aUnit ) { preselect_node_name = aComponentName.Lower(); + preselect_unit_number = aUnit; } @@ -123,71 +129,79 @@ void COMPONENT_TREE_SEARCH_CONTAINER::SetTree( wxTreeCtrl* aTree ) void COMPONENT_TREE_SEARCH_CONTAINER::AddLibrary( CMP_LIBRARY& aLib ) { - wxArrayString all_comp; + wxArrayString all_aliases; - aLib.GetEntryNames( all_comp ); - AddComponentList( aLib.GetName(), all_comp, &aLib, false ); + aLib.GetEntryNames( all_aliases ); + AddAliasList( aLib.GetName(), all_aliases, &aLib ); + ++libraries_added; } -void COMPONENT_TREE_SEARCH_CONTAINER::AddComponentList( const wxString& aNodeName, - const wxArrayString& aComponentNameList, - CMP_LIBRARY* aOptionalLib, - bool aNormallyExpanded ) +void COMPONENT_TREE_SEARCH_CONTAINER::AddAliasList( const wxString& aNodeName, + const wxArrayString& aAliasNameList, + CMP_LIBRARY* aOptionalLib ) { - TREE_NODE* parent_node = new TREE_NODE( NULL, NULL, aNodeName, wxEmptyString, wxEmptyString, - aNormallyExpanded ); + static const wxChar unitLetter[] = wxT( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ); - nodes.push_back( parent_node ); + TREE_NODE* const lib_node = new TREE_NODE( TREE_NODE::TYPE_LIB, NULL, NULL, + aNodeName, wxEmptyString, wxEmptyString ); + nodes.push_back( lib_node ); - BOOST_FOREACH( const wxString& cName, aComponentNameList ) + BOOST_FOREACH( const wxString& aName, aAliasNameList ) { - LIB_COMPONENT *c; + LIB_ALIAS* a; - if (aOptionalLib) - c = aOptionalLib->FindComponent( cName ); + if( aOptionalLib ) + a = aOptionalLib->FindAlias( aName ); else - c = CMP_LIBRARY::FindLibraryComponent( cName, wxEmptyString ); + a = CMP_LIBRARY::FindLibraryEntry( aName, wxEmptyString ); - if (c == NULL) + if( a == NULL ) continue; - wxString keywords, descriptions; + wxString search_text; + search_text = ( a->GetKeyWords().empty() ) ? wxT(" ") : a->GetKeyWords(); + search_text += a->GetDescription(); + wxString display_info; - for ( size_t i = 0; i < c->GetAliasCount(); ++i ) + if( !a->GetDescription().empty() ) { - LIB_ALIAS *a = c->GetAlias( i ); - keywords += a->GetKeyWords(); - descriptions += a->GetDescription(); - - if ( display_info.empty() && !a->GetDescription().empty() ) - { - // Preformatting. Unfortunately, the tree widget doesn't have columns - display_info.Printf( wxT(" %s[ %s ]"), - ( cName.length() <= 8 ) ? wxT("\t\t") : wxT("\t"), - GetChars( a->GetDescription() ) ); - } + // Preformatting. Unfortunately, the tree widget doesn't have columns + display_info.Printf( wxT(" %s[ %s ]"), + ( a->GetName().length() <= 8 ) ? wxT("\t\t") : wxT("\t"), + GetChars( a->GetDescription() ) ); } - // If there are no keywords, we give a couple of characters whitespace penalty. We want - // a component with a search-term found in the keywords score slightly higher than another - // component without keywords, but that term in the descriptions. - wxString search_text = ( !keywords.empty() ) ? keywords : wxT(" "); - search_text += descriptions; - nodes.push_back( new TREE_NODE( parent_node, c->GetLibrary(), - cName, display_info, search_text ) ); + TREE_NODE* alias_node = new TREE_NODE( TREE_NODE::TYPE_ALIAS, lib_node, + a, a->GetName(), display_info, search_text ); + nodes.push_back( alias_node ); + + if( a->GetComponent()->IsMulti() ) // Add all units as sub-nodes. + for ( int u = 0; u < a->GetComponent()->GetPartCount(); ++u ) + { + const wxString unitName = unitLetter[u]; + TREE_NODE* unit_node = new TREE_NODE(TREE_NODE::TYPE_UNIT, alias_node, a, + _("Unit ") + unitName, + wxEmptyString, wxEmptyString ); + unit_node->Unit = u + 1; + nodes.push_back( unit_node ); + } } } -LIB_COMPONENT* COMPONENT_TREE_SEARCH_CONTAINER::GetSelectedComponent() +LIB_ALIAS* COMPONENT_TREE_SEARCH_CONTAINER::GetSelectedAlias( int* aUnit ) { const wxTreeItemId& select_id = tree->GetSelection(); + BOOST_FOREACH( TREE_NODE* node, nodes ) { - if ( node->MatchScore > 0 && node->TreeId == select_id && node->Lib ) - return node->Lib->FindComponent( node->Name ); + if( node->MatchScore > 0 && node->TreeId == select_id ) { + if( aUnit && node->Unit > 0 ) + *aUnit = node->Unit; + return node->Alias; + } } return NULL; } @@ -209,7 +223,7 @@ static int matchPosScore(int aPosition, int aMaximum) void COMPONENT_TREE_SEARCH_CONTAINER::UpdateSearchTerm( const wxString& aSearch ) { - if ( tree == NULL ) + if( tree == NULL ) return; // We score the list by going through it several time, essentially with a complexity @@ -220,7 +234,7 @@ void COMPONENT_TREE_SEARCH_CONTAINER::UpdateSearchTerm( const wxString& aSearch BOOST_FOREACH( TREE_NODE* node, nodes ) { node->PreviousScore = node->MatchScore; - node->MatchScore = node->Parent ? kLowestDefaultScore : 0; // start-match for leafs. + node->MatchScore = ( node->Type == TREE_NODE::TYPE_LIB ) ? 0 : kLowestDefaultScore; } // Create match scores for each node for all the terms, that come space-separated. @@ -239,12 +253,13 @@ void COMPONENT_TREE_SEARCH_CONTAINER::UpdateSearchTerm( const wxString& aSearch while ( tokenizer.HasMoreTokens() ) { const wxString term = tokenizer.GetNextToken().Lower(); + BOOST_FOREACH( TREE_NODE* node, nodes ) { - if ( node->Parent == NULL) - continue; // Library nodes are not scored here. + if( node->Type != TREE_NODE::TYPE_ALIAS ) + continue; // Only aliases are actually scored here. - if ( node->MatchScore == 0) + if( node->MatchScore == 0) continue; // Leaf node without score are out of the game. // Keywords and description we only count if the match string is at @@ -252,16 +267,16 @@ void COMPONENT_TREE_SEARCH_CONTAINER::UpdateSearchTerm( const wxString& aSearch // matches. Most abbreviations are at three characters long. int found_pos; - if ( term == node->MatchName ) + if( term == node->MatchName ) node->MatchScore += 1000; // exact match. High score :) - else if ( (found_pos = node->MatchName.Find( term ) ) != wxNOT_FOUND ) + else if( (found_pos = node->MatchName.Find( term ) ) != wxNOT_FOUND ) { // Substring match. The earlier in the string the better. score += 20..40 node->MatchScore += matchPosScore( found_pos, 20 ) + 20; } - else if ( node->Parent->MatchName.Find( term ) != wxNOT_FOUND ) + else if( node->Parent->MatchName.Find( term ) != wxNOT_FOUND ) node->MatchScore += 19; // parent name matches. score += 19 - else if ( ( found_pos = node->SearchText.Find( term ) ) != wxNOT_FOUND ) + else if( ( found_pos = node->SearchText.Find( term ) ) != wxNOT_FOUND ) { // If we have a very short search term (like one or two letters), we don't want // to accumulate scores if they just happen to be in keywords or description as @@ -277,22 +292,35 @@ void COMPONENT_TREE_SEARCH_CONTAINER::UpdateSearchTerm( const wxString& aSearch } } - // Parent nodes have the maximum score seen in any of their children. + // Library nodes have the maximum score seen in any of their children. + // Alias nodes have the score of their parents. unsigned highest_score_seen = 0; bool any_change = false; + BOOST_FOREACH( TREE_NODE* node, nodes ) { - if ( node->Parent == NULL ) - continue; + switch( node->Type ) + { + case TREE_NODE::TYPE_ALIAS: + { + any_change |= (node->PreviousScore != node->MatchScore); + // Update library score. + node->Parent->MatchScore = std::max( node->Parent->MatchScore, node->MatchScore ); + highest_score_seen = std::max( highest_score_seen, node->MatchScore ); + } + break; - any_change |= (node->PreviousScore != node->MatchScore); - node->Parent->MatchScore = std::max( node->Parent->MatchScore, node->MatchScore ); - highest_score_seen = std::max( highest_score_seen, node->MatchScore ); + case TREE_NODE::TYPE_UNIT: + node->MatchScore = node->Parent->MatchScore; + break; + + default: + break; + } } - // The tree update might be slow, so we want to bail out if there is no change. - if ( !any_change ) + if( !any_change ) return; // Now: sort all items according to match score, libraries first. @@ -305,9 +333,10 @@ void COMPONENT_TREE_SEARCH_CONTAINER::UpdateSearchTerm( const wxString& aSearch const wxTreeItemId root_id = tree->AddRoot( wxEmptyString ); const TREE_NODE* first_match = NULL; const TREE_NODE* preselected_node = NULL; + BOOST_FOREACH( TREE_NODE* node, nodes ) { - if ( node->MatchScore == 0 ) + if( node->MatchScore == 0 ) continue; // If we have nodes that go beyond the default score, suppress nodes that @@ -315,42 +344,50 @@ void COMPONENT_TREE_SEARCH_CONTAINER::UpdateSearchTerm( const wxString& aSearch // some one-letter match in the keyword or description. In this case, we prefer matches // that just have higher scores. Improves relevancy and performance as the tree has to // display less items. - if ( highest_score_seen > kLowestDefaultScore && node->MatchScore == kLowestDefaultScore ) + if( highest_score_seen > kLowestDefaultScore && node->MatchScore == kLowestDefaultScore ) continue; - const bool isLeaf = ( node->Parent != NULL ); wxString node_text; #if 0 // Node text with scoring information for debugging - node_text.Printf( wxT("%s (s=%u)%s"), GetChars(node->Name), - node->MatchScore, GetChars(node->DisplayInfo)); + node_text.Printf( wxT("%s (s=%u)%s"), GetChars(node->DisplayName), + node->MatchScore, GetChars( node->DisplayInfo )); #else - node_text = node->Name + node->DisplayInfo; + node_text = node->DisplayName + node->DisplayInfo; #endif - node->TreeId = tree->AppendItem( !isLeaf ? root_id : node->Parent->TreeId, node_text ); + node->TreeId = tree->AppendItem( node->Parent ? node->Parent->TreeId : root_id, + node_text ); - // If we are a leaf node, we might need to expand. - if ( isLeaf ) + // If we are a nicely scored alias, we want to have it visible. Also, if there + // is only a single library in this container, we want to have it unfolded + // (example: power library). + if( node->Type == TREE_NODE::TYPE_ALIAS + && ( node->MatchScore > kLowestDefaultScore || libraries_added == 1 ) ) { - if ( node->MatchScore > kLowestDefaultScore ) - { - tree->EnsureVisible( node->TreeId ); + tree->EnsureVisible( node->TreeId ); - if ( first_match == NULL ) - first_match = node; // The "I am feeling lucky" element. - } - - if ( preselected_node == NULL && node->MatchName == preselect_node_name ) - preselected_node = node; + if( first_match == NULL ) + first_match = node; // First, highest scoring: the "I am feeling lucky" element. } - if ( !isLeaf && node->NormallyExpanded ) - tree->Expand( node->TreeId ); + // The first node that matches our pre-select criteria is choosen. 'First node' + // means, it shows up in the history, as the history node is displayed very first + // (by virtue of alphabetical ordering) + if( preselected_node == NULL + && node->Type == TREE_NODE::TYPE_ALIAS + && node->MatchName == preselect_node_name ) + preselected_node = node; + + // Refinement in case we come accross a matching unit node. + if( preselected_node != NULL && preselected_node->Type == TREE_NODE::TYPE_ALIAS + && node->Parent == preselected_node + && preselect_unit_number >= 1 && node->Unit == preselect_unit_number ) + preselected_node = node; } - if ( first_match ) // Highest score search match pre-selected. + if( first_match ) // Highest score search match pre-selected. tree->SelectItem( first_match->TreeId ); - else if ( preselected_node ) // No search, so history item preselected. + else if( preselected_node ) // No search, so history item preselected. tree->SelectItem( preselected_node->TreeId ); tree->Thaw(); diff --git a/eeschema/component_tree_search_container.h b/eeschema/component_tree_search_container.h index b89d1b2c6b..88bd52474f 100644 --- a/eeschema/component_tree_search_container.h +++ b/eeschema/component_tree_search_container.h @@ -21,11 +21,13 @@ * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#ifndef COMPONENT_TREE_SEARCH_CONTAINER_H +#define COMPONENT_TREE_SEARCH_CONTAINER_H #include #include -class LIB_COMPONENT; +class LIB_ALIAS; class CMP_LIBRARY; class wxTreeCtrl; class wxArrayString; @@ -44,7 +46,7 @@ public: ~COMPONENT_TREE_SEARCH_CONTAINER(); /** Function AddLibrary - * Add the components of this library to be searched. + * Add all the components and their aliases of this library to be searched. * To be called in the setup phase to fill this container. * * @param aLib containting all the components to be added. @@ -56,19 +58,19 @@ public: * To be called in the setup phase to fill this container. * * @param aNodeName The parent node name the components will show up as leaf. - * @param aComponentNameList List of component names. + * @param aAliasNameList List of alias names. * @param aOptionalLib Library to look up the component names (if NULL: global lookup) - * @param aNormallyExpanded Should the node in the tree be expanded by default. */ - void AddComponentList( const wxString& aNodeName, const wxArrayString& aComponentNameList, - CMP_LIBRARY* aOptionalLib, bool aNormallyExpanded ); + void AddAliasList( const wxString& aNodeName, const wxArrayString& aAliasNameList, + CMP_LIBRARY* aOptionalLib ); /** Function SetPreselectNode * Set the component name to be selected in absence of any search-result. * * @param aComponentName the component name to be selected. + * @param aUnit the component unit to be selected (if > 0). */ - void SetPreselectNode( const wxString& aComponentName ); + void SetPreselectNode( const wxString& aComponentName, int aUnit ); /** Function SetTree * Set the tree to be manipulated. @@ -92,17 +94,23 @@ public: */ void UpdateSearchTerm( const wxString& aSearch ); - /** Function GetSelectedComponent + /** Function GetSelectedAlias * - * @return the selected component or NULL if there is none. + * @param if not-NULL, the selected sub-unit is set here. + * @return the selected alias or NULL if there is none. */ - LIB_COMPONENT* GetSelectedComponent(); + LIB_ALIAS* GetSelectedAlias( int* aUnit ); private: struct TREE_NODE; static bool scoreComparator( const TREE_NODE* a1, const TREE_NODE* a2 ); std::vector nodes; - wxString preselect_node_name; wxTreeCtrl* tree; + int libraries_added; + + wxString preselect_node_name; + int preselect_unit_number; }; + +#endif /* COMPONENT_TREE_SEARCH_CONTAINER_H */ diff --git a/eeschema/dialogs/dialog_choose_component.cpp b/eeschema/dialogs/dialog_choose_component.cpp index 604c9cb94a..104e570d7e 100644 --- a/eeschema/dialogs/dialog_choose_component.cpp +++ b/eeschema/dialogs/dialog_choose_component.cpp @@ -35,77 +35,47 @@ static wxTreeItemId GetPrevItem( const wxTreeCtrl& tree, const wxTreeItemId& item ); static wxTreeItemId GetNextItem( const wxTreeCtrl& tree, const wxTreeItemId& item ); -// Combine descriptions of all aliases from given component. -static wxString combineDescriptions( LIB_COMPONENT* aComponent ) -{ - std::set descriptions; - - for( size_t i = 0; i < aComponent->GetAliasCount(); ++i ) - { - LIB_ALIAS* a = aComponent->GetAlias( i ); - - if ( !a->GetDescription().empty() ) - descriptions.insert( a->GetDescription() ); - } - - wxString result; - BOOST_FOREACH( const wxString& s, descriptions ) - result += s + wxT("\n"); - return result; -} - - -// Combine keywords. Keywords come as a string, but are considered space-separated -// individual words. Return a string with a unique set of these. -static wxString combineKeywords( LIB_COMPONENT* aComponent ) -{ - std::set keywords; - - for( size_t i = 0; i < aComponent->GetAliasCount(); ++i ) - { - LIB_ALIAS* a = aComponent->GetAlias( i ); - wxStringTokenizer tokenizer( a->GetKeyWords() ); - - while ( tokenizer.HasMoreTokens() ) - keywords.insert( tokenizer.GetNextToken() ); - } - - wxString result; - BOOST_FOREACH( const wxString& s, keywords ) - result += s + wxT(" "); - return result; -} - - DIALOG_CHOOSE_COMPONENT::DIALOG_CHOOSE_COMPONENT( wxWindow* aParent, const wxString& aTitle, - COMPONENT_TREE_SEARCH_CONTAINER* aContainer ) + COMPONENT_TREE_SEARCH_CONTAINER* aContainer, + int aDeMorganConvert ) : DIALOG_CHOOSE_COMPONENT_BASE( aParent, wxID_ANY, aTitle ), m_search_container( aContainer ), - m_selected_component( NULL ), + m_deMorganConvert( aDeMorganConvert >= 0 ? aDeMorganConvert : 0 ), m_external_browser_requested( false ), - m_received_doubleclick_in_tree( false ) + m_received_doubleclick_in_tree( false ), + m_ready_to_render( false ) { - // TODO: restore last size user was choosing. m_search_container->SetTree( m_libraryComponentTree ); m_searchBox->SetFocus(); m_componentDetails->SetEditable( false ); + m_componentView + ->Connect( wxEVT_PAINT, + wxPaintEventHandler( DIALOG_CHOOSE_COMPONENT::OnHandlePreviewRepaint ), + NULL, this ); + m_componentView + ->Connect( wxEVT_LEFT_UP, + wxMouseEventHandler( DIALOG_CHOOSE_COMPONENT::OnStartComponentBrowser ), + NULL, this ); + + m_ready_to_render = true; // Only after setup, we accept drawing updates. } -// After this dialog is done: return the component that has been selected, or an +// After this dialog is done: return the alias that has been selected, or an // empty string if there is none. -wxString DIALOG_CHOOSE_COMPONENT::GetSelectedComponentName() const +wxString DIALOG_CHOOSE_COMPONENT::GetSelectedAliasName( int* aUnit ) const { - if ( m_selected_component == NULL ) - return wxEmptyString; + LIB_ALIAS *alias = m_search_container->GetSelectedAlias( aUnit ); - return m_selected_component->GetName(); + if( alias ) + return alias->GetName(); + + return wxEmptyString; } void DIALOG_CHOOSE_COMPONENT::OnSearchBoxChange( wxCommandEvent& aEvent ) { - m_selected_component = NULL; m_search_container->UpdateSearchTerm( m_searchBox->GetLineText(0) ); updateSelection(); } @@ -117,31 +87,50 @@ void DIALOG_CHOOSE_COMPONENT::OnSearchBoxEnter( wxCommandEvent& aEvent ) } -void DIALOG_CHOOSE_COMPONENT::SelectIfValid( const wxTreeItemId& aTreeId ) +void DIALOG_CHOOSE_COMPONENT::selectIfValid( const wxTreeItemId& aTreeId ) { - if ( aTreeId.IsOk() && aTreeId != m_libraryComponentTree->GetRootItem() ) + if( aTreeId.IsOk() && aTreeId != m_libraryComponentTree->GetRootItem() ) m_libraryComponentTree->SelectItem( aTreeId ); } void DIALOG_CHOOSE_COMPONENT::OnInterceptSearchBoxKey( wxKeyEvent& aKeyStroke ) { - // Cursor up/down are forwarded to the tree. This is done by intercepting some navigational - // keystrokes that normally would go to the text search box (which has the focus by default). + // Cursor up/down and partiallyi cursor are use to do tree navigation operations. + // This is done by intercepting some navigational keystrokes that normally would go to + // the text search box (which has the focus by default). That way, we are mostly keyboard + // operable. + // (If the tree has the focus, it can handle that by itself). const wxTreeItemId sel = m_libraryComponentTree->GetSelection(); - switch ( aKeyStroke.GetKeyCode() ) + switch( aKeyStroke.GetKeyCode() ) { case WXK_UP: - SelectIfValid( GetPrevItem( *m_libraryComponentTree, sel ) ); + selectIfValid( GetPrevItem( *m_libraryComponentTree, sel ) ); break; case WXK_DOWN: - SelectIfValid( GetNextItem( *m_libraryComponentTree, sel ) ); + selectIfValid( GetNextItem( *m_libraryComponentTree, sel ) ); + break; + + // The follwoing keys we can only hijack if they are not needed by the textbox itself. + + case WXK_LEFT: + if( m_searchBox->GetInsertionPoint() == 0 ) + m_libraryComponentTree->Collapse( sel ); + else + aKeyStroke.Skip(); // Use for original purpose: move cursor. + break; + + case WXK_RIGHT: + if( m_searchBox->GetInsertionPoint() >= (long) m_searchBox->GetLineText( 0 ).length() ) + m_libraryComponentTree->Expand( sel ); + else + aKeyStroke.Skip(); // Use for original purpose: move cursor. break; default: - aKeyStroke.Skip(); // Pass on to search box. + aKeyStroke.Skip(); // Any other key: pass on to search box directly. break; } } @@ -155,9 +144,7 @@ void DIALOG_CHOOSE_COMPONENT::OnTreeSelect( wxTreeEvent& aEvent ) void DIALOG_CHOOSE_COMPONENT::OnDoubleClickTreeSelect( wxTreeEvent& aEvent ) { - updateSelection(); - - if ( m_selected_component == NULL ) + if( !updateSelection() ) return; // Ok, got selection. We don't just end the modal dialog here, but @@ -170,7 +157,7 @@ void DIALOG_CHOOSE_COMPONENT::OnDoubleClickTreeSelect( wxTreeEvent& aEvent ) void DIALOG_CHOOSE_COMPONENT::OnTreeMouseUp( wxMouseEvent& aMouseEvent ) { - if ( m_received_doubleclick_in_tree ) + if( m_received_doubleclick_in_tree ) EndModal( wxID_OK ); // We are done (see OnDoubleClickTreeSelect) else aMouseEvent.Skip(); // Let upstream handle it. @@ -184,20 +171,19 @@ void DIALOG_CHOOSE_COMPONENT::OnStartComponentBrowser( wxMouseEvent& aEvent ) } -void DIALOG_CHOOSE_COMPONENT::updateSelection() +bool DIALOG_CHOOSE_COMPONENT::updateSelection() { - LIB_COMPONENT* selection = m_search_container->GetSelectedComponent(); + int unit = 0; + LIB_ALIAS* selection = m_search_container->GetSelectedAlias( &unit ); - if ( selection == m_selected_component ) - return; // no change. - - m_selected_component = selection; + renderPreview( selection ? selection->GetComponent() : NULL, unit ); m_componentDetails->Clear(); - if ( m_selected_component == NULL ) - return; + if( selection == NULL ) + return false; + m_componentDetails->Freeze(); wxFont font_normal = m_componentDetails->GetFont(); wxFont font_bold = m_componentDetails->GetFont(); font_bold.SetWeight( wxFONTWEIGHT_BOLD ); @@ -207,20 +193,20 @@ void DIALOG_CHOOSE_COMPONENT::updateSelection() wxTextAttr text_attribute; text_attribute.SetFont(font_normal); - const wxString description = combineDescriptions( selection ); + const wxString description = selection->GetDescription(); - if ( !description.empty() ) + if( !description.empty() ) { m_componentDetails->SetDefaultStyle( headline_attribute ); m_componentDetails->AppendText( _("Description\n") ); m_componentDetails->SetDefaultStyle( text_attribute ); m_componentDetails->AppendText( description ); - m_componentDetails->AppendText( wxT("\n") ); + m_componentDetails->AppendText( wxT("\n\n") ); } - const wxString keywords = combineKeywords( selection ); + const wxString keywords = selection->GetKeyWords(); - if ( !keywords.empty() ) + if( !keywords.empty() ) { m_componentDetails->SetDefaultStyle( headline_attribute ); m_componentDetails->AppendText( _("Keywords\n") ); @@ -229,30 +215,110 @@ void DIALOG_CHOOSE_COMPONENT::updateSelection() } m_componentDetails->SetInsertionPoint( 0 ); // scroll up. + m_componentDetails->Thaw(); + + return true; } + +void DIALOG_CHOOSE_COMPONENT::OnHandlePreviewRepaint( wxPaintEvent& aRepaintEvent ) +{ + int unit = 0; + LIB_ALIAS* selection = m_search_container->GetSelectedAlias( &unit ); + + renderPreview( selection ? selection->GetComponent() : NULL, unit ); +} + + +// Render the preview in our m_componentView. If this gets more complicated, we should +// probably have a derived class from wxPanel; but this keeps things local. +void DIALOG_CHOOSE_COMPONENT::renderPreview( LIB_COMPONENT* aComponent, int aUnit ) +{ + if( !m_ready_to_render ) + return; + + wxPaintDC dc( m_componentView ); + dc.SetBackground( *wxWHITE_BRUSH ); + dc.Clear(); + + if( aComponent == NULL ) + return; + + if( aUnit <= 0 ) + aUnit = 1; + + const wxSize dc_size = dc.GetSize(); + dc.SetDeviceOrigin( dc_size.x / 2, dc_size.y / 2 ); + + // Find joint bounding box for everything we are about to draw. + EDA_RECT bBox; + + BOOST_FOREACH( LIB_ITEM& item, aComponent->GetDrawItemList() ) + { + if( ( item.GetUnit() && item.GetUnit() != aUnit ) + || ( item.GetConvert() && item.GetConvert() != m_deMorganConvert ) ) + continue; + bBox.Merge( item.GetBoundingBox() ); + } + + const double xscale = (double) dc_size.x / bBox.GetWidth(); + const double yscale = (double) dc_size.y / bBox.GetHeight(); + const double scale = std::min( xscale, yscale ) * 0.85; + + dc.SetUserScale( scale, scale ); + + wxPoint offset = bBox.Centre(); + NEGATE( offset.x ); + NEGATE( offset.y ); + + GRResetPenAndBrush( &dc ); + + BOOST_FOREACH( LIB_ITEM& item, aComponent->GetDrawItemList() ) + { + if( ( item.GetUnit() && item.GetUnit() != aUnit ) + || ( item.GetConvert() && item.GetConvert() != m_deMorganConvert ) ) + continue; + item.Draw( NULL, &dc, offset, UNSPECIFIED_COLOR, GR_COPY, + NULL, DefaultTransform ); + } +} + + static wxTreeItemId GetPrevItem( const wxTreeCtrl& tree, const wxTreeItemId& item ) { wxTreeItemId prevItem = tree.GetPrevSibling( item ); - if ( !prevItem.IsOk() ) + if( !prevItem.IsOk() ) { - const wxTreeItemId parent = tree.GetItemParent( item ); - prevItem = tree.GetLastChild( tree.GetPrevSibling( parent ) ); + prevItem = tree.GetItemParent( item ); + } + else if( tree.IsExpanded( prevItem ) ) + { + prevItem = tree.GetLastChild( prevItem ); } return prevItem; } + static wxTreeItemId GetNextItem( const wxTreeCtrl& tree, const wxTreeItemId& item ) { - wxTreeItemId nextItem = tree.GetNextSibling( item ); + wxTreeItemId nextItem; - if ( !nextItem.IsOk() ) + if( tree.IsExpanded( item ) ) { - const wxTreeItemId parent = tree.GetItemParent( item ); wxTreeItemIdValue dummy; - nextItem = tree.GetFirstChild( tree.GetNextSibling( parent ), dummy ); + nextItem = tree.GetFirstChild( item, dummy ); + } + else + { + // Walk up levels until we find one that has a next sibling. + for ( wxTreeItemId walk = item; walk.IsOk(); walk = tree.GetItemParent( walk ) ) + { + nextItem = tree.GetNextSibling( walk ); + if( nextItem.IsOk() ) + break; + } } return nextItem; diff --git a/eeschema/dialogs/dialog_choose_component.h b/eeschema/dialogs/dialog_choose_component.h index 3f02b74ef6..ec945a2c15 100644 --- a/eeschema/dialogs/dialog_choose_component.h +++ b/eeschema/dialogs/dialog_choose_component.h @@ -21,6 +21,8 @@ * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#ifndef DIALOG_CHOOSE_COMPONENT_H +#define DIALOG_CHOOSE_COMPONENT_H #include @@ -32,14 +34,16 @@ class DIALOG_CHOOSE_COMPONENT : public DIALOG_CHOOSE_COMPONENT_BASE { public: DIALOG_CHOOSE_COMPONENT( wxWindow* aParent, const wxString& aTitle, - COMPONENT_TREE_SEARCH_CONTAINER* aSearch_container ); + COMPONENT_TREE_SEARCH_CONTAINER* aSearch_container, + int aDeMorganConvert ); - /** Function GetSelectedComponentName + /** Function GetSelectedAliasName * To be called after this dialog returns from ShowModal(). * - * @return the component that has been selected, or an empty string if there is none. + * @param aUnit if not NULL, the selected unit is filled in here. + * @return the alias that has been selected, or an empty string if there is none. */ - wxString GetSelectedComponentName() const; + wxString GetSelectedAliasName( int* aUnit ) const; /** Function IsExternalBrowserSelected * @@ -57,13 +61,18 @@ protected: virtual void OnTreeMouseUp( wxMouseEvent& aMouseEvent ); virtual void OnStartComponentBrowser( wxMouseEvent& aEvent ); + virtual void OnHandlePreviewRepaint( wxPaintEvent& aRepaintEvent ); private: - void updateSelection(); - void SelectIfValid( const wxTreeItemId& aTreeId ); + bool updateSelection(); + void selectIfValid( const wxTreeItemId& aTreeId ); + void renderPreview( LIB_COMPONENT* aComponent, int aUnit ); COMPONENT_TREE_SEARCH_CONTAINER* const m_search_container; - LIB_COMPONENT* m_selected_component; + const int m_deMorganConvert; bool m_external_browser_requested; bool m_received_doubleclick_in_tree; + bool m_ready_to_render; }; + +#endif /* DIALOG_CHOOSE_COMPONENT_H */ diff --git a/eeschema/dialogs/dialog_choose_component_base.cpp b/eeschema/dialogs/dialog_choose_component_base.cpp index a9334549ba..3ce1599591 100644 --- a/eeschema/dialogs/dialog_choose_component_base.cpp +++ b/eeschema/dialogs/dialog_choose_component_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Nov 6 2013) +// C++ code generated with wxFormBuilder (version Feb 8 2014) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -11,7 +11,7 @@ DIALOG_CHOOSE_COMPONENT_BASE::DIALOG_CHOOSE_COMPONENT_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style ) { - this->SetSizeHints( wxSize( 450,-1 ), wxDefaultSize ); + this->SetSizeHints( wxSize( 450,100 ), wxDefaultSize ); wxBoxSizer* bSizer1; bSizer1 = new wxBoxSizer( wxVERTICAL ); @@ -37,35 +37,21 @@ DIALOG_CHOOSE_COMPONENT_BASE::DIALOG_CHOOSE_COMPONENT_BASE( wxWindow* parent, wx wxBoxSizer* bSizer3; bSizer3 = new wxBoxSizer( wxHORIZONTAL ); - m_componentView = new wxStaticText( this, wxID_ANY, wxT("TODO\n(mini. comp image)"), wxDefaultPosition, wxSize( 100,100 ), 0 ); - m_componentView->Wrap( -1 ); + m_componentView = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); m_componentView->SetMinSize( wxSize( 100,100 ) ); - bSizer3->Add( m_componentView, 0, wxALL, 5 ); + bSizer3->Add( m_componentView, 1, wxEXPAND | wxALL, 5 ); - wxBoxSizer* bSizer6; - bSizer6 = new wxBoxSizer( wxVERTICAL ); + m_componentDetails = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE ); + m_componentDetails->SetMinSize( wxSize( -1,100 ) ); - m_componentDetails = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,100 ), wxTE_MULTILINE ); - bSizer6->Add( m_componentDetails, 1, wxALL|wxEXPAND, 5 ); - - m_unitChoice = new wxComboBox( this, wxID_ANY, wxT("Unit A"), wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); - m_unitChoice->Enable( false ); - m_unitChoice->Hide(); - - bSizer6->Add( m_unitChoice, 0, wxALL, 5 ); - - - bSizer3->Add( bSizer6, 2, wxEXPAND, 5 ); + bSizer3->Add( m_componentDetails, 2, wxALL|wxEXPAND, 5 ); bSizer1->Add( bSizer3, 1, wxEXPAND, 5 ); wxBoxSizer* bSizer5; - bSizer5 = new wxBoxSizer( wxHORIZONTAL ); - - - bSizer5->Add( 0, 0, 1, wxEXPAND, 5 ); + bSizer5 = new wxBoxSizer( wxVERTICAL ); m_button = new wxStdDialogButtonSizer(); m_buttonOK = new wxButton( this, wxID_OK ); @@ -77,7 +63,7 @@ DIALOG_CHOOSE_COMPONENT_BASE::DIALOG_CHOOSE_COMPONENT_BASE( wxWindow* parent, wx bSizer5->Add( m_button, 0, wxEXPAND, 5 ); - bSizer1->Add( bSizer5, 0, wxEXPAND, 5 ); + bSizer1->Add( bSizer5, 0, wxALIGN_RIGHT, 5 ); this->SetSizer( bSizer1 ); @@ -92,7 +78,6 @@ DIALOG_CHOOSE_COMPONENT_BASE::DIALOG_CHOOSE_COMPONENT_BASE( wxWindow* parent, wx m_libraryComponentTree->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnTreeMouseUp ), NULL, this ); m_libraryComponentTree->Connect( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, wxTreeEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnDoubleClickTreeSelect ), NULL, this ); m_libraryComponentTree->Connect( wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnTreeSelect ), NULL, this ); - m_componentView->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnStartComponentBrowser ), NULL, this ); } DIALOG_CHOOSE_COMPONENT_BASE::~DIALOG_CHOOSE_COMPONENT_BASE() @@ -104,6 +89,5 @@ DIALOG_CHOOSE_COMPONENT_BASE::~DIALOG_CHOOSE_COMPONENT_BASE() m_libraryComponentTree->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnTreeMouseUp ), NULL, this ); m_libraryComponentTree->Disconnect( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, wxTreeEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnDoubleClickTreeSelect ), NULL, this ); m_libraryComponentTree->Disconnect( wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnTreeSelect ), NULL, this ); - m_componentView->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnStartComponentBrowser ), NULL, this ); } diff --git a/eeschema/dialogs/dialog_choose_component_base.fbp b/eeschema/dialogs/dialog_choose_component_base.fbp index 73cdcb2f83..b87834f800 100644 --- a/eeschema/dialogs/dialog_choose_component_base.fbp +++ b/eeschema/dialogs/dialog_choose_component_base.fbp @@ -1,6 +1,6 @@ - + C++ @@ -41,7 +41,7 @@ 0 wxID_ANY - 450,-1 + 450,100 DIALOG_CHOOSE_COMPONENT_BASE 450,500 @@ -389,11 +389,11 @@ bSizer3 wxHORIZONTAL none - + 5 - wxALL - 0 - + wxEXPAND | wxALL + 1 + 1 1 1 @@ -421,7 +421,6 @@ 0 0 wxID_ANY - TODO (mini. comp image) 0 @@ -438,15 +437,13 @@ Resizable 1 - 100,100 - + 0 - - -1 + wxTAB_TRAVERSAL @@ -456,7 +453,7 @@ - OnStartComponentBrowser + @@ -472,197 +469,95 @@ - + 5 - wxEXPAND + wxALL|wxEXPAND 2 - - - bSizer6 - wxVERTICAL - none - - 5 - wxALL|wxEXPAND - 1 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - - - 0 - -1,100 - 1 - m_componentDetails - 1 - - - protected - 1 - - Resizable - 1 - -1,-1 - wxTE_MULTILINE - - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - - 1 - - 1 - 0 - Dock - 0 - Left - 0 - - 1 - - 0 - 1 - wxID_ANY - - 0 - - - 0 - - 1 - m_unitChoice - 1 - - - protected - 1 - - Resizable - -1 - 1 - - - - 0 - - - wxFILTER_NONE - wxDefaultValidator - - Unit A - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + -1,100 + 1 + m_componentDetails + 1 + + + protected + 1 + + Resizable + 1 + -1,-1 + wxTE_MULTILINE + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_choose_component_base.h b/eeschema/dialogs/dialog_choose_component_base.h index 005aceb9cd..04c73b101f 100644 --- a/eeschema/dialogs/dialog_choose_component_base.h +++ b/eeschema/dialogs/dialog_choose_component_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Nov 6 2013) +// C++ code generated with wxFormBuilder (version Feb 8 2014) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -22,7 +22,7 @@ class DIALOG_SHIM; #include #include #include -#include +#include #include #include @@ -40,9 +40,8 @@ class DIALOG_CHOOSE_COMPONENT_BASE : public DIALOG_SHIM wxStaticText* m_searchLabel; wxTextCtrl* m_searchBox; wxTreeCtrl* m_libraryComponentTree; - wxStaticText* m_componentView; + wxPanel* m_componentView; wxTextCtrl* m_componentDetails; - wxComboBox* m_unitChoice; wxStdDialogButtonSizer* m_button; wxButton* m_buttonOK; wxButton* m_buttonCancel; @@ -54,7 +53,6 @@ class DIALOG_CHOOSE_COMPONENT_BASE : public DIALOG_SHIM virtual void OnTreeMouseUp( wxMouseEvent& event ) { event.Skip(); } virtual void OnDoubleClickTreeSelect( wxTreeEvent& event ) { event.Skip(); } virtual void OnTreeSelect( wxTreeEvent& event ) { event.Skip(); } - virtual void OnStartComponentBrowser( wxMouseEvent& event ) { event.Skip(); } public: diff --git a/eeschema/getpart.cpp b/eeschema/getpart.cpp index 4554e4f4be..e8031d3b86 100644 --- a/eeschema/getpart.cpp +++ b/eeschema/getpart.cpp @@ -81,6 +81,7 @@ wxString SCH_BASE_FRAME::SelectComponentFromLibBrowser( void ) wxString SCH_BASE_FRAME::SelectComponentFromLibrary( const wxString& aLibname, wxArrayString& aHistoryList, + int& aHistoryLastUnit, bool aUseLibBrowser, int* aUnit, int* aConvert ) @@ -113,17 +114,18 @@ wxString SCH_BASE_FRAME::SelectComponentFromLibrary( const wxString& aLibname, { // This is good for a transition for experineced users: giving them a History. Ideally, // we actually make this part even faster to access with a popup on ALT-a or something. - search_container.AddComponentList( _("-- History --"), aHistoryList, NULL, true ); - search_container.SetPreselectNode( aHistoryList[0] ); + search_container.AddAliasList( _("-- History --"), aHistoryList, NULL ); + search_container.SetPreselectNode( aHistoryList[0], aHistoryLastUnit ); } + const int deMorgan = aConvert ? *aConvert : 1; dialogTitle.Printf( _( "Choose Component (%d items loaded)" ), cmpCount ); - DIALOG_CHOOSE_COMPONENT dlg( this, dialogTitle, &search_container ); + DIALOG_CHOOSE_COMPONENT dlg( this, dialogTitle, &search_container, deMorgan ); if( dlg.ShowModal() == wxID_CANCEL ) return wxEmptyString; - wxString cmpName = dlg.GetSelectedComponentName(); + wxString cmpName = dlg.GetSelectedAliasName( aUnit ); if( dlg.IsExternalBrowserSelected() ) { @@ -137,7 +139,10 @@ wxString SCH_BASE_FRAME::SelectComponentFromLibrary( const wxString& aLibname, } if ( !cmpName.empty() ) + { AddHistoryComponentName( aHistoryList, cmpName ); + if ( aUnit ) aHistoryLastUnit = *aUnit; + } return cmpName; } @@ -146,6 +151,7 @@ wxString SCH_BASE_FRAME::SelectComponentFromLibrary( const wxString& aLibname, SCH_COMPONENT* SCH_EDIT_FRAME::Load_Component( wxDC* aDC, const wxString& aLibname, wxArrayString& aHistoryList, + int& aHistoryLastUnit, bool aUseLibBrowser ) { int unit = 1; @@ -153,8 +159,8 @@ SCH_COMPONENT* SCH_EDIT_FRAME::Load_Component( wxDC* aDC, SetRepeatItem( NULL ); m_canvas->SetIgnoreMouseEvents( true ); - wxString Name = SelectComponentFromLibrary( aLibname, aHistoryList, aUseLibBrowser, - &unit, &convert ); + wxString Name = SelectComponentFromLibrary( aLibname, aHistoryList, aHistoryLastUnit, + aUseLibBrowser, &unit, &convert ); if( Name.IsEmpty() ) { diff --git a/eeschema/lib_arc.cpp b/eeschema/lib_arc.cpp index c4a3735f8c..a93ecae90f 100644 --- a/eeschema/lib_arc.cpp +++ b/eeschema/lib_arc.cpp @@ -447,16 +447,18 @@ void LIB_ARC::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOf if( aColor >= 0 ) fill = NO_FILL; + EDA_RECT* const clipbox = aPanel? aPanel->GetClipBox() : NULL; + if( fill == FILLED_WITH_BG_BODYCOLOR ) { - GRFilledArc( aPanel->GetClipBox(), aDC, posc.x, posc.y, pt1, pt2, + GRFilledArc( clipbox, aDC, posc.x, posc.y, pt1, pt2, m_Radius, GetPenSize( ), (m_Flags & IS_MOVED) ? color : GetLayerColor( LAYER_DEVICE_BACKGROUND ), GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); } else if( fill == FILLED_SHAPE && !aData ) { - GRFilledArc( aPanel->GetClipBox(), aDC, posc.x, posc.y, pt1, pt2, m_Radius, + GRFilledArc( clipbox, aDC, posc.x, posc.y, pt1, pt2, m_Radius, color, color ); } else @@ -464,11 +466,11 @@ void LIB_ARC::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOf #ifdef DRAW_ARC_WITH_ANGLE - GRArc( aPanel->GetClipBox(), aDC, posc.x, posc.y, pt1, pt2, m_Radius, + GRArc( clipbox, aDC, posc.x, posc.y, pt1, pt2, m_Radius, GetPenSize(), color ); #else - GRArc1( aPanel->GetClipBox(), aDC, pos1.x, pos1.y, pos2.x, pos2.y, + GRArc1( clipbox, aDC, pos1.x, pos1.y, pos2.x, pos2.y, posc.x, posc.y, GetPenSize(), color ); #endif } @@ -477,7 +479,7 @@ void LIB_ARC::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOf * calculation. */ #if 0 EDA_RECT bBox = GetBoundingBox(); - GRRect( aPanel->GetClipBox(), aDC, bBox.GetOrigin().x, bBox.GetOrigin().y, + GRRect( clipbox, aDC, bBox.GetOrigin().x, bBox.GetOrigin().y, bBox.GetEnd().x, bBox.GetEnd().y, 0, LIGHTMAGENTA ); #endif } diff --git a/eeschema/lib_circle.cpp b/eeschema/lib_circle.cpp index 9dadd713fe..2110f42bf8 100644 --- a/eeschema/lib_circle.cpp +++ b/eeschema/lib_circle.cpp @@ -231,20 +231,21 @@ void LIB_CIRCLE::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& if( aColor >= 0 ) fill = NO_FILL; + EDA_RECT* const clipbox = aPanel? aPanel->GetClipBox() : NULL; if( fill == FILLED_WITH_BG_BODYCOLOR ) - GRFilledCircle( aPanel->GetClipBox(), aDC, pos1.x, pos1.y, m_Radius, GetPenSize(), + GRFilledCircle( clipbox, aDC, pos1.x, pos1.y, m_Radius, GetPenSize(), (m_Flags & IS_MOVED) ? color : GetLayerColor( LAYER_DEVICE_BACKGROUND ), GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); else if( fill == FILLED_SHAPE ) - GRFilledCircle( aPanel->GetClipBox(), aDC, pos1.x, pos1.y, m_Radius, 0, color, color ); + GRFilledCircle( clipbox, aDC, pos1.x, pos1.y, m_Radius, 0, color, color ); else - GRCircle( aPanel->GetClipBox(), aDC, pos1.x, pos1.y, m_Radius, GetPenSize(), color ); + GRCircle( clipbox, aDC, pos1.x, pos1.y, m_Radius, GetPenSize(), color ); /* Set to one (1) to draw bounding box around circle to validate bounding * box calculation. */ #if 0 EDA_RECT bBox = GetBoundingBox(); - GRRect( aPanel->GetClipBox(), aDC, bBox.GetOrigin().x, bBox.GetOrigin().y, + GRRect( clipbox, aDC, bBox.GetOrigin().x, bBox.GetOrigin().y, bBox.GetEnd().x, bBox.GetEnd().y, 0, LIGHTMAGENTA ); #endif } diff --git a/eeschema/lib_polyline.cpp b/eeschema/lib_polyline.cpp index 2b3fabc71b..49aa1daf42 100644 --- a/eeschema/lib_polyline.cpp +++ b/eeschema/lib_polyline.cpp @@ -296,15 +296,16 @@ void LIB_POLYLINE::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint GRSetDrawMode( aDC, aDrawMode ); + EDA_RECT* const clipbox = aPanel? aPanel->GetClipBox() : NULL; if( fill == FILLED_WITH_BG_BODYCOLOR ) - GRPoly( aPanel->GetClipBox(), aDC, m_PolyPoints.size(), buffer, 1, GetPenSize(), + GRPoly( clipbox, aDC, m_PolyPoints.size(), buffer, 1, GetPenSize(), (m_Flags & IS_MOVED) ? color : GetLayerColor( LAYER_DEVICE_BACKGROUND ), GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); else if( fill == FILLED_SHAPE ) - GRPoly( aPanel->GetClipBox(), aDC, m_PolyPoints.size(), buffer, 1, GetPenSize(), + GRPoly( clipbox, aDC, m_PolyPoints.size(), buffer, 1, GetPenSize(), color, color ); else - GRPoly( aPanel->GetClipBox(), aDC, m_PolyPoints.size(), buffer, 0, GetPenSize(), + GRPoly( clipbox, aDC, m_PolyPoints.size(), buffer, 0, GetPenSize(), color, color ); delete[] buffer; @@ -314,7 +315,7 @@ void LIB_POLYLINE::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint #if 0 EDA_RECT bBox = GetBoundingBox(); bBox.Inflate( m_Thickness + 1, m_Thickness + 1 ); - GRRect( aPanel->GetClipBox(), aDC, bBox.GetOrigin().x, bBox.GetOrigin().y, + GRRect( clipbox, aDC, bBox.GetOrigin().x, bBox.GetOrigin().y, bBox.GetEnd().x, bBox.GetEnd().y, 0, LIGHTMAGENTA ); #endif } diff --git a/eeschema/lib_rectangle.cpp b/eeschema/lib_rectangle.cpp index 42c7a1b395..4ba9ab959e 100644 --- a/eeschema/lib_rectangle.cpp +++ b/eeschema/lib_rectangle.cpp @@ -222,22 +222,23 @@ void LIB_RECTANGLE::drawGraphic( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GRSetDrawMode( aDC, aDrawMode ); + EDA_RECT* const clipbox = aPanel? aPanel->GetClipBox() : NULL; if( fill == FILLED_WITH_BG_BODYCOLOR && !aData ) - GRFilledRect( aPanel->GetClipBox(), aDC, pos1.x, pos1.y, pos2.x, pos2.y, GetPenSize( ), + GRFilledRect( clipbox, aDC, pos1.x, pos1.y, pos2.x, pos2.y, GetPenSize( ), (m_Flags & IS_MOVED) ? color : GetLayerColor( LAYER_DEVICE_BACKGROUND ), GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); else if( m_Fill == FILLED_SHAPE && !aData ) - GRFilledRect( aPanel->GetClipBox(), aDC, pos1.x, pos1.y, pos2.x, pos2.y, + GRFilledRect( clipbox, aDC, pos1.x, pos1.y, pos2.x, pos2.y, GetPenSize(), color, color ); else - GRRect( aPanel->GetClipBox(), aDC, pos1.x, pos1.y, pos2.x, pos2.y, GetPenSize(), color ); + GRRect( clipbox, aDC, pos1.x, pos1.y, pos2.x, pos2.y, GetPenSize(), color ); /* Set to one (1) to draw bounding box around rectangle to validate * bounding box calculation. */ #if 0 EDA_RECT bBox = GetBoundingBox(); bBox.Inflate( m_Thickness + 1, m_Thickness + 1 ); - GRRect( aPanel->GetClipBox(), aDC, bBox.GetOrigin().x, bBox.GetOrigin().y, + GRRect( clipbox, aDC, bBox.GetOrigin().x, bBox.GetOrigin().y, bBox.GetEnd().x, bBox.GetEnd().y, 0, LIGHTMAGENTA ); #endif } diff --git a/eeschema/libedit.cpp b/eeschema/libedit.cpp index e5f3b6511d..9236467b6d 100644 --- a/eeschema/libedit.cpp +++ b/eeschema/libedit.cpp @@ -131,8 +131,10 @@ void LIB_EDIT_FRAME::LoadOneLibraryPart( wxCommandEvent& event ) return; } - wxArrayString historyList; - CmpName = SelectComponentFromLibrary( m_library->GetName(), historyList, true, NULL, NULL ); + wxArrayString dummyHistoryList; + int dummyLastUnit; + CmpName = SelectComponentFromLibrary( m_library->GetName(), dummyHistoryList, dummyLastUnit, + true, NULL, NULL ); if( CmpName.IsEmpty() ) return; diff --git a/eeschema/onleftclick.cpp b/eeschema/onleftclick.cpp index 9bf9dcea0e..8a5a6adcaa 100644 --- a/eeschema/onleftclick.cpp +++ b/eeschema/onleftclick.cpp @@ -46,8 +46,13 @@ #include +// TODO(hzeller): These pairs of elmenets should be represented by an object, but don't want +// to refactor too much right now to not get in the way with other code changes. static wxArrayString s_CmpNameList; +static int s_CmpLastUnit; + static wxArrayString s_PowerNameList; +static int s_LastPowerUnit; void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) @@ -294,7 +299,8 @@ void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) case ID_SCH_PLACE_COMPONENT: if( (item == NULL) || (item->GetFlags() == 0) ) { - GetScreen()->SetCurItem( Load_Component( aDC, wxEmptyString, s_CmpNameList, true ) ); + GetScreen()->SetCurItem( Load_Component( aDC, wxEmptyString, + s_CmpNameList, s_CmpLastUnit, true ) ); m_canvas->SetAutoPanRequest( true ); } else @@ -307,7 +313,7 @@ void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) if( ( item == NULL ) || ( item->GetFlags() == 0 ) ) { GetScreen()->SetCurItem( Load_Component( aDC, wxT( "power" ), - s_PowerNameList, false ) ); + s_PowerNameList, s_LastPowerUnit, false ) ); m_canvas->SetAutoPanRequest( true ); } else diff --git a/include/sch_base_frame.h b/include/sch_base_frame.h index e53634a28d..c2c7e8b011 100644 --- a/include/sch_base_frame.h +++ b/include/sch_base_frame.h @@ -89,21 +89,24 @@ protected: * Calls the library viewer to select component to import into schematic. * if the library viewer is currently running, it is closed and reopened * in modal mode. - * @param aLibname = the lib name or an empty string. - * if aLibname is empty, the full list of libraries is used - * @param aHistoryList = list of previously loaded components - * @param aUseLibBrowser = bool to call the library viewer to select the component - * @param aUnit = a point to int to return the selected unit (if any) - * @param aConvert = a point to int to return the selected De Morgan shape (if any) + * @param aLibname the lib name or an empty string. + * if aLibname is empty, the full list of libraries is used + * @param aHistoryList list of previously loaded components + * @param aHistoryLastUnit remembering last unit in last component. + * @param aUseLibBrowser bool to call the library viewer to select the component + * @param aUnit a pointer to int to return the selected unit (if any) + * @param aConvert a pointer to int to return the selected De Morgan shape (if any) * * @return the component name */ wxString SelectComponentFromLibrary( const wxString& aLibname, wxArrayString& aHistoryList, + int& aHistoryLastUnit, bool aUseLibBrowser, int* aUnit, int* aConvert ); + /** * Function OnOpenLibraryViewer * Open the library viewer only to browse library contents. diff --git a/include/wxEeschemaStruct.h b/include/wxEeschemaStruct.h index badc7d0150..9956a37778 100644 --- a/include/wxEeschemaStruct.h +++ b/include/wxEeschemaStruct.h @@ -1001,10 +1001,16 @@ private: * loads from a library and places a component. * if libname != "", search in lib "libname" * else search in all loaded libs + * + * @param aHistoryList list remembering recently used component names. + * @param aHistoryLastUnit remembering last unit in last component. + * (TODO(hzeller): This really should be a class doing history, but didn't + * want to change too much while other refactoring is going on) */ SCH_COMPONENT* Load_Component( wxDC* DC, const wxString& libname, - wxArrayString& List, + wxArrayString& aHistoryList, + int& aHistoryLastUnit, bool UseLibBrowser ); /**