//TODO: Tooltips for error messages void CodeChecker::OnTooltip(CodeBlocksEvent& e) { EditorBase *edb=e.GetEditor(); if(!edb->IsBuiltinEditor()) return; cbEditor *ed=(cbEditor *)edb; int lexer=ed->GetControl()->GetLexer(); if(m_commands.find(lexer)==m_commands.end()) return; /* NOTE: The following 2 lines of codes can fix [Bug #11785]. * The solution may not the best one and it requires the editor * to have the focus (even if C::B has the focus) in order to pop-up the tooltip. */ if (wxWindow::FindFocus() != static_cast<wxWindow*>(ed->GetControl())) return; int pos = ed->GetControl()->PositionFromPointClose(e.GetX(), e.GetY()); if(pos==wxSCI_INVALID_POSITION) return; int line = ed->GetControl()->LineFromPosition(pos); if(m_issues.find(ed->GetFilename())==m_issues.end()) return; CodeIssues &ci=m_issues[ed->GetFilename()]; for(CodeIssues::iterator it=ci.begin();it!=ci.end();++it) if(line==it->line) { if (ed->GetControl()->CallTipActive()) ed->GetControl()->CallTipCancel(); // LogMessage(wxString::Format(_("Tooltip dear: X - %i, Y - %i, pos - %i"),e.GetX(),e.GetY(),pos)); wxString msg=it->msg;//_T("Goodnight Dear"); ed->GetControl()->CallTipShow(pos, msg); } }
void PythonDebugger::OnValueTooltip(CodeBlocksEvent& event) { event.Skip(); if (!m_DebuggerActive) return; if (!IsStopped()) return; EditorBase* base = event.GetEditor(); cbEditor* ed = base && base->IsBuiltinEditor() ? static_cast<cbEditor*>(base) : 0; if (!ed) return; if(ed->IsContextMenuOpened()) { return; } // get rid of other calltips (if any) [for example the code completion one, at this time we // want the debugger value call/tool-tip to win and be shown] if(ed->GetControl()->CallTipActive()) { ed->GetControl()->CallTipCancel(); } const int style = event.GetInt(); if (style != wxSCI_P_DEFAULT && style != wxSCI_P_OPERATOR && style != wxSCI_P_IDENTIFIER && style != wxSCI_P_CLASSNAME) return; wxPoint pt; pt.x = event.GetX(); pt.y = event.GetY(); int pos = ed->GetControl()->PositionFromPoint(pt); int start = ed->GetControl()->WordStartPosition(pos, true); int end = ed->GetControl()->WordEndPosition(pos, true); while(ed->GetControl()->GetCharAt(start-1)==_T('.')) start=ed->GetControl()->WordStartPosition(start-2, true); wxString token; if (start >= ed->GetControl()->GetSelectionStart() && end <= ed->GetControl()->GetSelectionEnd()) { token = ed->GetControl()->GetSelectedText(); } else token = ed->GetControl()->GetTextRange(start,end); if (token.IsEmpty()) return; wxString cmd; cmd+=_T("pw ")+token+_T("\n"); DispatchCommands(cmd,DBGCMDTYPE_WATCHTOOLTIP,true); m_watch_tooltip_pos=pos; }
void cbDebuggerPlugin::ProcessValueTooltip(CodeBlocksEvent& event) { event.Skip(); if (cbDebuggerCommonConfig::GetFlag(cbDebuggerCommonConfig::RequireCtrlForTooltips)) { if (!wxGetKeyState(WXK_CONTROL)) return; } if (Manager::Get()->GetDebuggerManager()->GetInterfaceFactory()->IsValueTooltipShown()) return; if (!ShowValueTooltip(event.GetInt())) return; EditorBase* base = event.GetEditor(); cbEditor* ed = base && base->IsBuiltinEditor() ? static_cast<cbEditor*>(base) : nullptr; if (!ed) return; if (ed->IsContextMenuOpened()) return; // get rid of other calltips (if any) [for example the code completion one, at this time we // want the debugger value call/tool-tip to win and be shown] if (ed->GetControl()->CallTipActive()) ed->GetControl()->CallTipCancel(); wxPoint pt; pt.x = event.GetX(); pt.y = event.GetY(); const wxString &token = GetEditorWordAtCaret(&pt); if (!token.empty()) { pt = ed->GetControl()->ClientToScreen(pt); OnValueTooltip(token, wxRect(pt.x - 5, pt.y, 10, 10)); } }
void SpellCheckerPlugin::OnEditorTooltip(CodeBlocksEvent& event) { if ( !IsAttached() || wxGetKeyState(WXK_CONTROL) || !(m_sccfg->GetEnableSpellTooltips() || m_sccfg->GetEnableThesaurusTooltips())) { event.Skip(); return; } EditorBase* base = event.GetEditor(); cbEditor* ed = base && base->IsBuiltinEditor() ? static_cast<cbEditor*>(base) : 0; if ( !ed || ed->IsContextMenuOpened() || wxWindow::FindFocus() != static_cast<wxWindow*>(ed->GetControl()) ) { event.Skip(); return; } cbStyledTextCtrl* stc = ed->GetControl(); if (!stc) return; int pos = stc->PositionFromPointClose(event.GetX(), event.GetY()); if (pos < 0 || pos >= stc->GetLength()) { event.Skip(); return; } wxString tip; int wordstart = pos, wordend = pos; while (wordstart) { if ( m_pSpellHelper->IsWhiteSpace( stc->GetCharAt(wordstart - 1) ) ) break; --wordstart; } while ( wordend < stc->GetLength() ) { if ( m_pSpellHelper->IsWhiteSpace( stc->GetCharAt(++wordend) ) ) break; } int tipWidth = 0; if ( m_sccfg->GetEnableSpellTooltips() && m_pSpellChecker->IsInitialized() && stc->IndicatorValueAt(m_pOnlineChecker->GetIndicator(), pos)) { // indicator is on -> check if we can find a suggestion wxString misspelledWord = stc->GetTextRange(wordstart, wordend); m_suggestions = m_pSpellChecker->GetSuggestions(misspelledWord); if (!m_suggestions.IsEmpty()) { // allow maximum 12 entries in 3 rows int lineWidth = 0; for (size_t i = 0; i < 12 && i < m_suggestions.size(); ++i) { tip << m_suggestions[i]; lineWidth += m_suggestions[i].Length(); if (i % 4 == 3) { tip << wxT(",\n"); if (lineWidth > tipWidth) tipWidth = lineWidth; lineWidth = 0; } else { tip << wxT(", "); lineWidth += 2; } } tip.RemoveLast(2); lineWidth -= 2; if (lineWidth > tipWidth) // in case the last line was not full, and thereby not checked tipWidth = lineWidth; } } else if ( m_sccfg->GetEnableThesaurusTooltips() && m_pThesaurus->IsOk() && m_pSpellHelper->HasStyleToBeChecked(ed->GetColourSet()->GetLanguageName(ed->GetLanguage()), event.GetInt())) { wxString word = stc->GetTextRange(wordstart, wordend); synonyms syn = m_pThesaurus->GetSynonyms(word); if (!syn.size()) // if not found, try lower case syn = m_pThesaurus->GetSynonyms(word.Lower()); if (syn.size()) { wxArrayString usedSyns; // avoid duplicate synonyms // allow maximum 12 entries in 4 rows synonyms::iterator it = syn.begin(); for (size_t i = 0; i < 4 && it != syn.end(); ++i, ++it) { wxString tipLine(it->first + wxT(": ")); std::vector< wxString > syns = syn[it->first]; size_t j = 0; for (size_t k = 0; k < 3 && j < syns.size(); ++j, ++k) { if (usedSyns.Index(syns[j]) == wxNOT_FOUND) { tipLine << syns[j] << wxT(", "); usedSyns.Add(syns[j]); } else --k; // synonym already listed, look for another word } tipLine.RemoveLast(2); if (tipLine.Length() > static_cast<size_t>(tipWidth)) tipWidth = tipLine.Length(); tip << tipLine << wxT("\n"); } tip.RemoveLast(); } } if (tip.IsEmpty()) { event.Skip(); return; } if (stc->CallTipActive()) stc->CallTipCancel(); // calculation from CC const int lnStart = stc->PositionFromLine(stc->LineFromPosition(pos)); // pos - lnStart == distance from start of line // + tipWidth + 1 == projected virtual position of tip end (with a 1 character buffer) from start of line // - (width_of_editor_in_pixels / width_of_character) == distance tip extends past window edge // horizontal scrolling is accounted for by PointFromPosition().x const int offset = tipWidth + pos + 1 - lnStart - (stc->GetSize().x - stc->PointFromPosition(lnStart).x) / stc->TextWidth(wxSCI_STYLE_LINENUMBER, _T("W")); if (offset > 0) pos -= offset; if (pos < lnStart) // do not go to previous line if tip is wider than editor pos = lnStart; stc->CallTipShow(pos, tip); event.SetExtraLong(1); // notify CC not to cancel this tooltip event.Skip(); }
// cbEVT_EDITOR_TOOLTIP void CCManager::OnEditorTooltip(CodeBlocksEvent& event) { event.Skip(); if (wxGetKeyState(WXK_CONTROL)) return; EditorBase* base = event.GetEditor(); cbEditor* ed = base && base->IsBuiltinEditor() ? static_cast<cbEditor*>(base) : nullptr; if (!ed || ed->IsContextMenuOpened()) return; cbStyledTextCtrl* stc = ed->GetControl(); cbCodeCompletionPlugin* ccPlugin = GetProviderFor(ed); int pos = stc->PositionFromPointClose(event.GetX(), event.GetY()); if (!ccPlugin || pos < 0 || pos >= stc->GetLength()) { if (stc->CallTipActive() && event.GetExtraLong() == 0 && m_CallTipActive == wxSCI_INVALID_POSITION) static_cast<wxScintilla*>(stc)->CallTipCancel(); return; } int hlStart, hlEnd, argsPos; hlStart = hlEnd = argsPos = wxSCI_INVALID_POSITION; bool allowCallTip = true; const std::vector<cbCodeCompletionPlugin::CCToken>& tokens = ccPlugin->GetTokenAt(pos, ed, allowCallTip); std::set<wxString> uniqueTips; for (size_t i = 0; i < tokens.size(); ++i) uniqueTips.insert(tokens[i].displayName); wxStringVec tips(uniqueTips.begin(), uniqueTips.end()); const int style = event.GetInt(); if (!tips.empty()) { const int tknStart = stc->WordStartPosition(pos, true); const int tknEnd = stc->WordEndPosition(pos, true); if (tknEnd - tknStart > 2) { for (size_t i = 0; i < tips[0].Length(); ++i) { size_t hlLoc = tips[0].find(stc->GetTextRange(tknStart, tknEnd), i); if (hlLoc == wxString::npos) break; hlStart = hlLoc; hlEnd = hlStart + tknEnd - tknStart; if ( (hlStart > 0 && (tips[0][hlStart - 1] == wxT('_') || wxIsalpha(tips[0][hlStart - 1]))) || (hlEnd < static_cast<int>(tips[0].Length()) - 1 && (tips[0][hlEnd] == wxT('_') || wxIsalpha(tips[0][hlEnd]))) ) { i = hlEnd; hlStart = hlEnd = wxSCI_INVALID_POSITION; } else break; } } } else if ( allowCallTip && !( stc->IsString(style) || stc->IsComment(style) || stc->IsCharacter(style) || stc->IsPreprocessor(style) ) ) { const int line = stc->LineFromPosition(pos); if (pos + 4 > stc->PositionFromLine(line) + (int)ed->GetLineIndentString(line).Length()) { const CallTipVec& cTips = ccPlugin->GetCallTips(pos, style, ed, argsPos); for (size_t i = 0; i < cTips.size(); ++i) tips.push_back(cTips[i].tip); if (!tips.empty()) { hlStart = cTips[0].hlStart; hlEnd = cTips[0].hlEnd; } } } if (tips.empty()) { if (stc->CallTipActive() && event.GetExtraLong() == 0 && m_CallTipActive == wxSCI_INVALID_POSITION) static_cast<wxScintilla*>(stc)->CallTipCancel(); } else { DoShowTips(tips, stc, pos, argsPos, hlStart, hlEnd); event.SetExtraLong(1); } m_CallTipActive = wxSCI_INVALID_POSITION; }