[FarGroup/FarManager] master: Color handling improvements (ffde26080)

0 views
Skip to first unread message

farg...@farmanager.com

unread,
Mar 12, 2026, 8:30:50 PMMar 12
to farco...@googlegroups.com
Repository : https://github.com/FarGroup/FarManager
On branch : master
Link : https://github.com/FarGroup/FarManager/commit/ffde26080b23a2d7bfcce0be4226c62ca759ad42

>---------------------------------------------------------------

commit ffde26080b23a2d7bfcce0be4226c62ca759ad42
Author: Alex Alabuzhev <alab...@gmail.com>
Date: Fri Mar 13 00:24:05 2026 +0000

Color handling improvements


>---------------------------------------------------------------

ffde26080b23a2d7bfcce0be4226c62ca759ad42
far/changelog | 5 +++++
far/color_picker.cpp | 7 +++++++
far/colormix.cpp | 21 ++++++++++-----------
far/colormix.hpp | 2 +-
far/vbuild.m4 | 2 +-
5 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/far/changelog b/far/changelog
index c15031c7a..530d5d0de 100644
--- a/far/changelog
+++ b/far/changelog
@@ -1,3 +1,8 @@
+--------------------------------------------------------------------------------
+drkns 2026-03-13 00:23:35+00:00 - build 6660
+
+1. Color handling improvements.
+
--------------------------------------------------------------------------------
drkns 2026-03-12 19:14:39+00:00 - build 6659

diff --git a/far/color_picker.cpp b/far/color_picker.cpp
index d039c16aa..86a2bc016 100644
--- a/far/color_picker.cpp
+++ b/far/color_picker.cpp
@@ -130,6 +130,7 @@ static std::optional<COLORREF> parse_color(string_view const Str, bool const IsI

// BUGBUG
static bool IgnoreEditChange = false;
+static bool IgnoreUpdateColorCode = false;
static bool IgnoreColorIndexClick = false;

constexpr auto
@@ -434,6 +435,9 @@ intptr_t single_color_state::GetSingleColorDlgProc(Dialog* Dlg, intptr_t Msg, in

if (TransparencyEnabled && colors::is_transparent(CurColor.Value))
{
+ IgnoreUpdateColorCode = true;
+ SCOPE_EXIT{ IgnoreUpdateColorCode = false; };
+
Dlg->SendMessage(DM_SETCHECK, Offset + cb::color_active_checkbox, ToPtr(BSTATE_UNCHECKED));
Dlg->SendMessage(DN_BTNCLICK, Offset + cb::color_active_checkbox, ToPtr(BSTATE_UNCHECKED));
}
@@ -442,6 +446,9 @@ intptr_t single_color_state::GetSingleColorDlgProc(Dialog* Dlg, intptr_t Msg, in

case DM_UPDATECOLORCODE:
{
+ if (IgnoreUpdateColorCode)
+ return false;
+
IgnoreEditChange = true;
SCOPE_EXIT{ IgnoreEditChange = false; };

diff --git a/far/colormix.cpp b/far/colormix.cpp
index ba427fede..7c874a260 100644
--- a/far/colormix.cpp
+++ b/far/colormix.cpp
@@ -292,7 +292,7 @@ namespace colors
Value.UnderlineColor);
}

- FarColor merge(FarColor Bottom, FarColor Top)
+ FarColor merge(FarColor const& Bottom, FarColor const& Top)
{
static FarColor LastResult, LastBottom, LastTop;

@@ -304,7 +304,7 @@ namespace colors

auto Result = Bottom;

- const auto merge_part = [&](COLORREF FarColor::*ColorAccessor, const FARCOLORFLAGS Flag)
+ const auto merge_part = [&Result, &Top](COLORREF FarColor::*ColorAccessor, const FARCOLORFLAGS Flag)
{
const auto TopValue = std::invoke(ColorAccessor, Top);

@@ -325,11 +325,9 @@ namespace colors
}

// Alpha blending
- const auto BottomValue = std::invoke(ColorAccessor, Bottom);
-
if (
TopValue == std::invoke(ColorAccessor, LastTop) && (Top.Flags & Flag) == (LastTop.Flags & Flag) &&
- BottomValue == std::invoke(ColorAccessor, LastBottom) && (Bottom.Flags & Flag) == (LastBottom.Flags & Flag)
+ ResultValue == std::invoke(ColorAccessor, LastBottom) && (Result.Flags & Flag) == (LastBottom.Flags & Flag)
)
{
ResultValue = std::invoke(ColorAccessor, LastResult);
@@ -343,11 +341,11 @@ namespace colors
};

const auto TopRGBA = to_rgba(TopValue, (Top.Flags & Flag) != 0);
- const auto BottomRGBA = to_rgba(BottomValue, (Bottom.Flags & Flag) != 0);
+ const auto ResultRGBA = to_rgba(ResultValue, (Result.Flags & Flag) != 0);

const auto calc_channel = [&](unsigned char rgba::*Accessor)
{
- return static_cast<unsigned char>((std::invoke(Accessor, TopRGBA) * TopRGBA.a + (0xFF - TopRGBA.a) * std::invoke(Accessor, BottomRGBA)) / 0xFF);
+ return static_cast<unsigned char>((std::invoke(Accessor, TopRGBA) * TopRGBA.a + (0xFF - TopRGBA.a) * std::invoke(Accessor, ResultRGBA)) / 0xFF);
};

rgba const MergedRGBA
@@ -355,7 +353,7 @@ namespace colors
calc_channel(&rgba::r),
calc_channel(&rgba::g),
calc_channel(&rgba::b),
- static_cast<unsigned char>(BottomRGBA.a | ((0xFF - BottomRGBA.a) * TopRGBA.a / 0xFF))
+ static_cast<unsigned char>(ResultRGBA.a | ((0xFF - ResultRGBA.a) * TopRGBA.a / 0xFF))
};

ResultValue = to_color(MergedRGBA);
@@ -365,10 +363,11 @@ namespace colors
merge_part(&FarColor::BackgroundColor, FCF_BG_INDEX);
merge_part(&FarColor::ForegroundColor, FCF_FG_INDEX);

- if (colors::is_transparent(Bottom.UnderlineColor))
+ if (is_transparent(Result.UnderlineColor) && !is_transparent(Top.UnderlineColor) && !is_opaque(Top.UnderlineColor))
{
- Bottom.SetUnderlineIndex(Bottom.IsFgIndex());
- Bottom.UnderlineColor = Bottom.ForegroundColor;
+ // We need something to work with if the bottom underline is not set and the top is translucent to any extent
+ Result.SetUnderlineIndex(Result.IsFgIndex());
+ Result.UnderlineColor = Result.ForegroundColor;
}

merge_part(&FarColor::UnderlineColor, FCF_FG_UNDERLINE_INDEX);
diff --git a/far/colormix.hpp b/far/colormix.hpp
index 2c3268b72..43ac3458b 100644
--- a/far/colormix.hpp
+++ b/far/colormix.hpp
@@ -119,7 +119,7 @@ namespace colors

size_t color_hash(const FarColor& Value);

- FarColor merge(FarColor Bottom, FarColor Top);
+ FarColor merge(FarColor const& Bottom, FarColor const& Top);

using palette_t = std::array<COLORREF, 256>;
palette_t const& default_palette();
diff --git a/far/vbuild.m4 b/far/vbuild.m4
index 031d72d5c..c52c7eb88 100644
--- a/far/vbuild.m4
+++ b/far/vbuild.m4
@@ -1 +1 @@
-6659
+6660


Reply all
Reply to author
Forward
0 new messages