Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Cleanup color handling in QgsCodeEditor classes
Remove a bunch of duplicate default color definitions, and ensure
that all subclasses correctly respect any user defined color overrides,
yet that we still default to following the application theme's matching
color schemes.
  • Loading branch information
nyalldawson committed Oct 3, 2020
1 parent b7c28df commit 6078fe4
Show file tree
Hide file tree
Showing 9 changed files with 522 additions and 107 deletions.
77 changes: 77 additions & 0 deletions python/gui/auto_generated/qgscodeeditor.sip.in
Expand Up @@ -70,6 +70,83 @@ Insert text at cursor position, or replace any selected text if user has
made a selection.

:param text: The text to be inserted
%End

enum class ColorRole
{
Default,
Keyword,
Class,
Method,
Decoration,
Number,
Comment,
CommentLine,
CommentBlock,
Background,
Cursor,
CaretLine,
SingleQuote,
DoubleQuote,
TripleSingleQuote,
TripleDoubleQuote,
Operator,
QuotedOperator,
Identifier,
QuotedIdentifier,
Tag,
UnknownTag,
MarginBackground,
MarginForeground,
SelectionBackground,
SelectionForeground,
MatchedBraceBackground,
MatchedBraceForeground,
Edge,
Fold,
Error,
};

static QColor defaultColor( ColorRole role, const QString &theme = QString() );
%Docstring
Returns the default color for the specified ``role``.

The optional ``theme`` argument can be used to specify a color ``theme``. A blank
``theme`` indicates the default color scheme.

Possible ``theme`` values are:

- (empty string) follow application default colors
- solarized
- solarized_dark

.. versionadded:: 3.16
%End

static QColor color( ColorRole role );
%Docstring
Returns the color to use in the editor for the specified ``role``.

This color will be the default theme color for the role, unless the user has manually
selected a custom color scheme for the editor.

.. seealso:: :py:func:`setColor`

.. versionadded:: 3.16
%End

static void setColor( ColorRole role, const QColor &color );
%Docstring
Sets the ``color`` to use in the editor for the specified ``role``.

This color will be stored as the new default color for the role, to be used for all code editors.

Set ``color`` to an invalid QColor in order to clear the stored color value and reset it to
the default color.

.. seealso:: :py:func:`color`

.. versionadded:: 3.16
%End

protected:
Expand Down
272 changes: 251 additions & 21 deletions src/gui/qgscodeeditor.cpp
Expand Up @@ -26,6 +26,42 @@
#include <QDebug>
#include <QFocusEvent>

QMap< QgsCodeEditor::ColorRole, QString > QgsCodeEditor::sColorRoleToSettingsKey
{
{ColorRole::Default, QStringLiteral( "defaultFontColor" ) },
{ColorRole::Keyword, QStringLiteral( "keywordFontColor" ) },
{ColorRole::Class, QStringLiteral( "classFontColor" ) },
{ColorRole::Method, QStringLiteral( "methodFontColor" ) },
{ColorRole::Decoration, QStringLiteral( "decoratorFontColor" ) },
{ColorRole::Number, QStringLiteral( "numberFontColor" ) },
{ColorRole::Comment, QStringLiteral( "commentFontColor" ) },
{ColorRole::CommentLine, QStringLiteral( "commentLineFontColor" ) },
{ColorRole::CommentBlock, QStringLiteral( "commentBlockFontColor" ) },
{ColorRole::Background, QStringLiteral( "paperBackgroundColor" ) },
{ColorRole::Cursor, QStringLiteral( "cursorColor" ) },
{ColorRole::CaretLine, QStringLiteral( "caretLineColor" ) },
{ColorRole::Operator, QStringLiteral( "operatorFontColor" ) },
{ColorRole::QuotedOperator, QStringLiteral( "quotedOperatorFontColor" ) },
{ColorRole::Identifier, QStringLiteral( "identifierFontColor" ) },
{ColorRole::QuotedIdentifier, QStringLiteral( "quotedIdentifierFontColor" ) },
{ColorRole::Tag, QStringLiteral( "tagFontColor" ) },
{ColorRole::UnknownTag, QStringLiteral( "unknownTagFontColor" ) },
{ColorRole::SingleQuote, QStringLiteral( "singleQuoteFontColor" ) },
{ColorRole::DoubleQuote, QStringLiteral( "doubleQuoteFontColor" ) },
{ColorRole::TripleSingleQuote, QStringLiteral( "tripleSingleQuoteFontColor" ) },
{ColorRole::TripleDoubleQuote, QStringLiteral( "tripleDoubleQuoteFontColor" ) },
{ColorRole::MarginBackground, QStringLiteral( "marginBackgroundColor" ) },
{ColorRole::MarginForeground, QStringLiteral( "marginForegroundColor" ) },
{ColorRole::SelectionBackground, QStringLiteral( "selectionBackgroundColor" ) },
{ColorRole::SelectionForeground, QStringLiteral( "selectionForegroundColor" ) },
{ColorRole::MatchedBraceBackground, QStringLiteral( "matchedBraceBackground" ) },
{ColorRole::MatchedBraceForeground, QStringLiteral( "matchedBraceColor" ) },
{ColorRole::Edge, QStringLiteral( "edgeColor" ) },
{ColorRole::Fold, QStringLiteral( "foldColor" ) },
{ColorRole::Error, QStringLiteral( "stderrFontColor" ) },
};


QgsCodeEditor::QgsCodeEditor( QWidget *parent, const QString &title, bool folding, bool margin )
: QsciScintilla( parent )
, mWidgetTitle( title )
Expand Down Expand Up @@ -94,38 +130,28 @@ void QgsCodeEditor::keyPressEvent( QKeyEvent *event )

void QgsCodeEditor::setSciWidget()
{
QHash< QString, QColor > colors;
if ( QgsApplication::instance()->themeName() != QStringLiteral( "default" ) )
{
QSettings ini( QgsApplication::instance()->uiThemes().value( QgsApplication::instance()->themeName() ) + "/qscintilla.ini", QSettings::IniFormat );
for ( const auto &key : ini.allKeys() )
{
colors.insert( key, QgsSymbolLayerUtils::decodeColor( ini.value( key ).toString() ) );
}
}
QPalette pal = qApp->palette();

QFont font = getMonospaceFont();
setFont( font );

setUtf8( true );
setCaretLineVisible( true );
setCaretLineBackgroundColor( colors.value( QStringLiteral( "caretLineColor" ), QColor( 252, 243, 237 ) ) );
setCaretForegroundColor( colors.value( QStringLiteral( "cursorColor" ), QColor( 51, 51, 51 ) ) );
setSelectionForegroundColor( colors.value( QStringLiteral( "selectionForegroundColor" ), pal.color( QPalette::HighlightedText ) ) );
setSelectionBackgroundColor( colors.value( QStringLiteral( "selectionBackgroundColor" ), pal.color( QPalette::Highlight ) ) );
setCaretLineBackgroundColor( color( ColorRole::CaretLine ) );
setCaretForegroundColor( color( ColorRole::Cursor ) );
setSelectionForegroundColor( color( ColorRole::SelectionForeground ) );
setSelectionBackgroundColor( color( ColorRole::SelectionBackground ) );

setBraceMatching( QsciScintilla::SloppyBraceMatch );
setMatchedBraceBackgroundColor( colors.value( QStringLiteral( "matchedBraceColor" ), QColor( 183, 249, 7 ) ) );
setMatchedBraceForegroundColor( color( ColorRole::MatchedBraceForeground ) );
setMatchedBraceBackgroundColor( color( ColorRole::MatchedBraceBackground ) );
// whether margin will be shown
setMarginVisible( mMargin );
setMarginsForegroundColor( colors.value( QStringLiteral( "marginForegroundColor" ), QColor( 62, 62, 227 ) ) );
setMarginsBackgroundColor( colors.value( QStringLiteral( "marginBackgroundColor" ), QColor( 249, 249, 249 ) ) );
setIndentationGuidesForegroundColor( colors.value( QStringLiteral( "marginForegroundColor" ), QColor( 62, 62, 227 ) ) );
setIndentationGuidesBackgroundColor( colors.value( QStringLiteral( "marginBackgroundColor" ), QColor( 249, 249, 249 ) ) );
setMarginsForegroundColor( color( ColorRole::MarginForeground ) );
setMarginsBackgroundColor( color( ColorRole::MarginBackground ) );
setIndentationGuidesForegroundColor( color( ColorRole::MarginForeground ) );
setIndentationGuidesBackgroundColor( color( ColorRole::MarginBackground ) );
// whether margin will be shown
setFoldingVisible( mFolding );
QColor foldColor = colors.value( QStringLiteral( "foldColor" ), QColor( 244, 244, 244 ) );
QColor foldColor = color( ColorRole::Fold );
setFoldMarginColors( foldColor, foldColor );
// indentation
setAutoIndent( true );
Expand Down Expand Up @@ -190,6 +216,210 @@ void QgsCodeEditor::insertText( const QString &text )
}
}

QColor QgsCodeEditor::defaultColor( QgsCodeEditor::ColorRole role, const QString &theme )
{
static QMap< QString, QMap< ColorRole, QColor > > sColors
{
{
QString(),
{
{ColorRole::Default, QColor( "#4d4d4c" ) },
{ColorRole::Keyword, QColor( "#8959a8" ) },
{ColorRole::Class, QColor( "#4271ae" ) },
{ColorRole::Method, QColor( "#4271ae" ) },
{ColorRole::Decoration, QColor( "#3e999f" ) },
{ColorRole::Number, QColor( "#c82829" ) },
{ColorRole::Comment, QColor( "#8e908c" ) },
{ColorRole::CommentLine, QColor( "#8e908c" ) },
{ColorRole::CommentBlock, QColor( "#8e908c" ) },
{ColorRole::Background, QColor( "#ffffff" ) },
{ColorRole::Operator, QColor( "#8959a8" ) },
{ColorRole::QuotedOperator, QColor( "#8959a8" ) },
{ColorRole::Identifier, QColor( "#4271ae" ) },
{ColorRole::QuotedIdentifier, QColor( "#4271ae" ) },
{ColorRole::Tag, QColor( "#4271ae" ) },
{ColorRole::UnknownTag, QColor( "#4271ae" ) },
{ColorRole::Cursor, QColor( "#636363" ) },
{ColorRole::CaretLine, QColor( "#efefef" ) },
{ColorRole::SingleQuote, QColor( "#718c00" ) },
{ColorRole::DoubleQuote, QColor( "#718c00" ) },
{ColorRole::TripleSingleQuote, QColor( "#eab700" ) },
{ColorRole::TripleDoubleQuote, QColor( "#eab700" ) },
{ColorRole::MarginBackground, QColor( "#efefef" ) },
{ColorRole::MarginForeground, QColor( "#636363" ) },
{ColorRole::SelectionBackground, QColor( "#d7d7d7" ) },
{ColorRole::SelectionForeground, QColor( "#303030" ) },
{ColorRole::MatchedBraceBackground, QColor( "#b7f907" ) },
{ColorRole::MatchedBraceForeground, QColor( "#303030" ) },
{ColorRole::Edge, QColor( "#efefef" ) },
{ColorRole::Fold, QColor( "#efefef" ) },
{ColorRole::Error, QColor( "#e31a1c" ) },
},
},
{
QStringLiteral( "solarized" ),
{
{ColorRole::Default, QColor( "#627c84" ) },
{ColorRole::Keyword, QColor( "#b79b00" ) },
{ColorRole::Class, QColor( "#008fd5" ) },
{ColorRole::Method, QColor( "#008fd5" ) },
{ColorRole::Decoration, QColor( "#b79b00" ) },
{ColorRole::Number, QColor( "#008fd5" ) },
{ColorRole::Comment, QColor( "#93a2a3" ) },
{ColorRole::CommentLine, QColor( "#93a2a3" ) },
{ColorRole::CommentBlock, QColor( "#93a2a3" ) },
{ColorRole::Background, QColor( "#fef6e4" ) },
{ColorRole::Cursor, QColor( "#cfcfcf" ) },
{ColorRole::CaretLine, QColor( "#f0e8d6" ) },
{ColorRole::Operator, QColor( "#b79b00" ) },
{ColorRole::QuotedOperator, QColor( "#b79b00" ) },
{ColorRole::Identifier, QColor( "#008fd5" ) },
{ColorRole::QuotedIdentifier, QColor( "#008fd5" ) },
{ColorRole::Tag, QColor( "#008fd5" ) },
{ColorRole::UnknownTag, QColor( "#008fd5" ) },
{ColorRole::SingleQuote, QColor( "#3da59e" ) },
{ColorRole::DoubleQuote, QColor( "#3da59e" ) },
{ColorRole::TripleSingleQuote, QColor( "#3da59e" ) },
{ColorRole::TripleDoubleQuote, QColor( "#3da59e" ) },
{ColorRole::MarginBackground, QColor( "#f0e8d6" ) },
{ColorRole::MarginForeground, QColor( "#93a2a3" ) },
{ColorRole::SelectionBackground, QColor( "#d7d7d7" ) },
{ColorRole::SelectionForeground, QColor( "#000000" ) },
{ColorRole::MatchedBraceBackground, QColor( "#b7f907" ) },
{ColorRole::MatchedBraceForeground, QColor( "#363636" ) },
{ColorRole::Edge, QColor( "#f0e8d6" ) },
{ColorRole::Fold, QColor( "#f0e8d6" ) },
{ColorRole::Error, QColor( "#e31a1c" ) },
},
},
{
QStringLiteral( "solarized_dark" ),
{
{ColorRole::Default, QColor( "#f6f3e8" ) },
{ColorRole::Keyword, QColor( "#6cbcf7" ) },
{ColorRole::Class, QColor( "#b3e765" ) },
{ColorRole::Method, QColor( "#ed5d36" ) },
{ColorRole::Decoration, QColor( "#6cbcf7" ) },
{ColorRole::Number, QColor( "#ed5d36" ) },
{ColorRole::Comment, QColor( "#b3e765" ) },
{ColorRole::CommentLine, QColor( "#b3e765" ) },
{ColorRole::CommentBlock, QColor( "#aeaeae" ) },
{ColorRole::Background, QColor( "#1f1f1f" ) },
{ColorRole::Cursor, QColor( "#cfcfcf" ) },
{ColorRole::CaretLine, QColor( "#363636" ) },
{ColorRole::Operator, QColor( "#6cbcf7" ) },
{ColorRole::QuotedOperator, QColor( "#6cbcf7" ) },
{ColorRole::Identifier, QColor( "#b3e765" ) },
{ColorRole::QuotedIdentifier, QColor( "#b3e765" ) },
{ColorRole::Tag, QColor( "#ed5d36" ) },
{ColorRole::UnknownTag, QColor( "#ed5d36" ) },
{ColorRole::SingleQuote, QColor( "#65b042" ) },
{ColorRole::DoubleQuote, QColor( "#65b042" ) },
{ColorRole::TripleSingleQuote, QColor( "#65b042" ) },
{ColorRole::TripleDoubleQuote, QColor( "#65b042" ) },
{ColorRole::MarginBackground, QColor( "#000000" ) },
{ColorRole::MarginForeground, QColor( "#9d9d9d" ) },
{ColorRole::SelectionBackground, QColor( "#d7d7d7" ) },
{ColorRole::SelectionForeground, QColor( "#000000" ) },
{ColorRole::MatchedBraceBackground, QColor( "#b7f907" ) },
{ColorRole::MatchedBraceForeground, QColor( "#363636" ) },
{ColorRole::Edge, QColor( "#3a3a3a" ) },
{ColorRole::Fold, QColor( "#3a3a3a" ) },
{ColorRole::Error, QColor( "#e31a1c" ) },
}
}
};

if ( theme.isEmpty() && QgsApplication::instance()->themeName() == QStringLiteral( "default" ) )
{
// if using default theme, take certain colors from the palette
QPalette pal = qApp->palette();

switch ( role )
{
case ColorRole::SelectionBackground:
return pal.color( QPalette::Highlight );
case ColorRole::SelectionForeground:
return pal.color( QPalette::HighlightedText );
default:
break;
}
}
else if ( theme.isEmpty() )
{
// non default theme (e.g. Blend of Gray). Take colors from theme ini file...
const QSettings ini( QgsApplication::instance()->uiThemes().value( QgsApplication::instance()->themeName() ) + "/qscintilla.ini", QSettings::IniFormat );

static QMap< ColorRole, QString > sColorRoleToIniKey
{
{ColorRole::Default, QStringLiteral( "python/defaultFontColor" ) },
{ColorRole::Keyword, QStringLiteral( "python/keywordFontColor" ) },
{ColorRole::Class, QStringLiteral( "python/classFontColor" ) },
{ColorRole::Method, QStringLiteral( "python/methodFontColor" ) },
{ColorRole::Decoration, QStringLiteral( "python/decoratorFontColor" ) },
{ColorRole::Number, QStringLiteral( "python/numberFontColor" ) },
{ColorRole::Comment, QStringLiteral( "python/commentFontColor" ) },
{ColorRole::CommentLine, QStringLiteral( "sql/commentLineFontColor" ) },
{ColorRole::CommentBlock, QStringLiteral( "python/commentBlockFontColor" ) },
{ColorRole::Background, QStringLiteral( "python/paperBackgroundColor" ) },
{ColorRole::Cursor, QStringLiteral( "cursorColor" ) },
{ColorRole::CaretLine, QStringLiteral( "caretLineColor" ) },
{ColorRole::Operator, QStringLiteral( "sql/operatorFontColor" ) },
{ColorRole::QuotedOperator, QStringLiteral( "sql/QuotedOperatorFontColor" ) },
{ColorRole::Identifier, QStringLiteral( "sql/identifierFontColor" ) },
{ColorRole::QuotedIdentifier, QStringLiteral( "sql/QuotedIdentifierFontColor" ) },
{ColorRole::Tag, QStringLiteral( "html/tagFontColor" ) },
{ColorRole::UnknownTag, QStringLiteral( "html/unknownTagFontColor" ) },
{ColorRole::SingleQuote, QStringLiteral( "sql/singleQuoteFontColor" ) },
{ColorRole::DoubleQuote, QStringLiteral( "sql/doubleQuoteFontColor" ) },
{ColorRole::TripleSingleQuote, QStringLiteral( "python/tripleSingleQuoteFontColor" ) },
{ColorRole::TripleDoubleQuote, QStringLiteral( "python/tripleDoubleQuoteFontColor" ) },
{ColorRole::MarginBackground, QStringLiteral( "marginBackgroundColor" ) },
{ColorRole::MarginForeground, QStringLiteral( "marginForegroundColor" ) },
{ColorRole::SelectionBackground, QStringLiteral( "selectionBackgroundColor" ) },
{ColorRole::SelectionForeground, QStringLiteral( "selectionForegroundColor" ) },
{ColorRole::MatchedBraceBackground, QStringLiteral( "matchedBraceBackground" ) },
{ColorRole::MatchedBraceForeground, QStringLiteral( "matchedBraceColor" ) },
{ColorRole::Edge, QStringLiteral( "edgeColor" ) },
{ColorRole::Fold, QStringLiteral( "foldColor" ) },
{ColorRole::Error, QStringLiteral( "stderrFontColor" ) },
};

return QgsSymbolLayerUtils::decodeColor( ini.value( sColorRoleToIniKey.value( role ), sColors.value( QString() ).value( role ).name() ).toString() );
}

return sColors.value( theme ).value( role );
}

QColor QgsCodeEditor::color( QgsCodeEditor::ColorRole role )
{
const QgsSettings settings;

if ( !settings.value( QStringLiteral( "codeEditor/overrideColors" ), false, QgsSettings::Gui ).toBool() )
{
const QString theme = settings.value( QStringLiteral( "codeEditor/colorScheme" ), QString(), QgsSettings::Gui ).toString();
return defaultColor( role, theme );
}
else
{
const QString color = settings.value( QStringLiteral( "codeEditor/%1" ).arg( sColorRoleToSettingsKey.value( role ) ), QString(), QgsSettings::Gui ).toString();
return color.isEmpty() ? defaultColor( role ) : QgsSymbolLayerUtils::decodeColor( color );
}
}

void QgsCodeEditor::setColor( QgsCodeEditor::ColorRole role, const QColor &color )
{
QgsSettings settings;
if ( color.isValid() )
{
settings.setValue( QStringLiteral( "codeEditor/%1" ).arg( sColorRoleToSettingsKey.value( role ) ), color.name(), QgsSettings::Gui );
}
else
{
settings.remove( QStringLiteral( "codeEditor/%1" ).arg( sColorRoleToSettingsKey.value( role ) ), QgsSettings::Gui );
}
}

// Settings for font and fontsize
bool QgsCodeEditor::isFixedPitch( const QFont &font )
{
Expand Down

0 comments on commit 6078fe4

Please sign in to comment.