Skip to content

Conversation

@rustedusted
Copy link

Allow bar meters to enable "sub-pixel" rendering.

Bar meter styles can be changed in setup (F2) under Display Options.

Co-Authored-By: Benny Baumann [email protected]

@rustedusted
Copy link
Author

referencing with issue #647
the previous merge request was a mess

@rustedusted
Copy link
Author

One more thing
the bar type option is visible in F2 even when we do htop -U should i disable it when opened with -U
or keep it there??

the function didn't have any if statement in it so felt awkward to do that
it's just a line of difference to add

@rustedusted
Copy link
Author

[x] Resolve the conflict marker in the latest commit(not using the previous commit)
[x] Handle storing the setting to disk
[ ] Proper guarding against invalid barType settings in Meter.c(i do not understand this, i just put asserts in the Meter.c line 168)(please let me know if there's anything else)
[x] Handle when htop is configured without Unicode support(done using header guards #ifdef HAVE_LIBNCURSESW)
[x] Update Commit message

@BenBE BenBE linked an issue Oct 25, 2025 that may be closed by this pull request
@BenBE BenBE added the enhancement Extension or improvement to existing feature label Oct 25, 2025
Settings.c Outdated
this->hideFunctionBar = atoi(option[1]);
#ifdef HAVE_LIBNCURSESW
} else if (String_eq(option[0], "bar_type")) {
this->barType = atoi(option[1]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value read here isn't protected against an invalid configuration file. Please ensure, that the value in this->barType is sanitized to be a valid bar type index.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be a good idea to set this->barType to 0 whenever we read an invalid value from the config. This makes the field forward-compatible to any future extensions of the list. Also, we should use strtol for parsing this field to get a defined behavior on integer overflow.

Unfortunately we don't have a macro to easily produce code like this one:

{
   long value = strtol(option[1], NULL, 10);
   if (value < 0 || value > BAR_METER_NUM_STYLES)
      value = 0;
   this->barType = (unsigned int)value;
}

Comment on lines 181 to +184
blockSizes[i] = ceil((value / this->total) * w);
blockSizes[i] = MINIMUM(blockSizes[i], w - offset);

#ifdef HAVE_LIBNCURSESW
extraWidth = (int)ceil((value / this->total) * w * barLen) % barLen;
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs some minor update. The extraWidth calculation probably should re-use the value calculated in the blockSizes[i] assignments above.

Meter.c Outdated
Comment on lines 93 to 99
L"||||||||",
L"########",
L"⣿⡀⡄⡆⡇⣇⣧⣷",
L"█░░▒▒▓▓█",
L"█▏▎▍▌▋▊▉",
L"█▁▂▃▄▅▆▇",
L"█▌▌▌▌███",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having the full block final seems more natural. Any reason to put it first and skip the per-profile blank instead?

Panel_add(super, (Object*) NumberItem_newByRef("Hide main function bar (0 - off, 1 - on ESC until next input, 2 - permanently)", &(settings->hideFunctionBar), 0, 0, 2));

#ifdef HAVE_LIBNCURSESW
Panel_add(super, (Object*) NumberItem_newByRef("Bar Type (0-6)", &(settings->barType), 0, 0, 6));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe 0 = default to avoid having this needing to updated whenever there's a new character theme.

Settings.h Outdated
#endif
int hideFunctionBar; // 0 - off, 1 - on ESC until next input, 2 - permanently
#ifdef HAVE_LIBNCURSESW
int barType;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not to use unsigned int for this field?

assert(settings->barType < ( sizeof(bars) / sizeof(wchar_t*) ));
assert(settings->barType >= 0);
const wchar_t* currBar = bars[settings->barType];
int barLen = (int)wcslen(currBar);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I consider this function call redundant when you have declared the list of bars to have equal length.

Not sure if this is what you intended, but I think the bar meter characters can be defined with variable widths if you wish.

Like this:

static const wchar_t* BarMeterMode_drawStyles[] = {
   L"|",
   L"#",
   L"⡀⡄⡆⡇⣇⣧⣷⣿",
   L"░▒▓█",
   L"▏▎▍▌▋▊▉█",
   L"▁▂▃▄▅▆▇█",
   L"▌█",
};

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bars currently have all the same length, but the intention is to actually allow for bars to contain different number of symbols.

Meter.c Outdated
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this include line. wchar.h is better included indirectly via ProvideCurses.h.

Meter.c Outdated
#include <float.h>
#include <limits.h> // IWYU pragma: keep
#include <math.h>
#include <stdio.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't see any stdio.h function being used at all in this PR.

@BenBE
Copy link
Member

BenBE commented Oct 25, 2025

Please squash/fixup changes into the original commit by rebasing. Details are in the style guide.

@rustedusted rustedusted force-pushed the feature-647 branch 2 times, most recently from 39d372a to 5f1a7a9 Compare October 26, 2025 07:39
Allow bar meters to enable "sub-pixel" rendering.

Bar meter styles can be changed in setup (F2) under Display Options.

Co-Authored-By: Benny Baumann <[email protected]>
@rustedusted
Copy link
Author

here's the latest commit that contains all the suggested things

assert(settings->barType < ( sizeof(bars) / sizeof(wchar_t*) ));
assert(settings->barType >= 0);
const wchar_t* currBar = bars[settings->barType];
int barLen = (int)wcslen(currBar);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bars currently have all the same length, but the intention is to actually allow for bars to contain different number of symbols.

(1 << LED_METERMODE) | \
0) // Avoids edits when updating

#define BAR_METER_NUM_STYLES 7
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define BAR_METER_NUM_STYLES 7
extern const size_t bar_meter_num_styles;

And below the definition of bars' for the meter styles in Meter.c`:

const size_t bar_meter_num_styles = sizeof(bars) / sizeof(*bars);

This avoids an additional point of manual updating.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BenBE This has the problem that when compiling Setting.c, compiler cannot inline the constant but has to refer to the external variable for the number. In other words, the compiled code would be sub-optimal.

I think the better approach is to move the definitions of the bar styles into the header. Look at the unitPrefixes definition in XUtils.h for what I mean.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm aware of this downside, but AFAICT there are no real places where looking up this constant happens inside a tight loop …

Meter.c Outdated
} else {
}
#ifdef HAVE_LIBNCURSESW
else if(CRT_utf8 && settings->barType) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole block of else if (CRT_utf8 && settings->barType) { ... } can merge with the else { ... } block below so we can reduce duplicate code.

#endif
int hideFunctionBar; // 0 - off, 1 - on ESC until next input, 2 - permanently
#ifdef HAVE_LIBNCURSESW
unsigned int barType;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the proposed bar drawing styles has | (vertical bar, the default), and # (number sign), both can be drawn in ASCII-only mode, I think we can remove the #ifdef HAVE_LIBNCURSESW conditional and allow the setting to be available in both ASCII-only build and Unicode build of htop.

Note: only the first two drawing styles can be selected in ASCII. The rest can be guarded in the #ifdef HAVE_LIBNCURSESW so they require Unicode to enable:

#ifdef HAVE_LIBNCURSESW
static const wchar_t* barMeterDrawStyles[] = {
   L"|",
   L"#",
   L"⡀⡄⡆⡇⣇⣧⣷⣿",
   L"░▒▓█",
   L"▏▎▍▌▋▊▉█",
   L"▁▂▃▄▅▆▇█",
   L"▌█",
};
#else
static const char* barMeterDrawStyles[] = {
   "|",
   "#"
};
#endif
static const size_t numBarMeterStyles = ARRAYSIZE(barMeterDrawStyles);

for (int j = offset; j < nextOffset; j++)
for (int j = offset; j < nextOffset; j++) {
if (RichString_getCharVal(bar, startPos + j) == ' ') {
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is one thing I wish to add when the feature of changing bar drawing character is added. It's this:

Suggested change
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
if (CRT_colorScheme == COLORSCHEME_MONOCHROME && Meter_maxItems(this) != 1) {

Make the bar character changeable for meters with only one item.

--- a/Meter.h
+++ b/Meter.h
@@ -100,6 +100,7 @@ typedef struct MeterClass_ {
 #define Meter_attributes(this_)        As_Meter(this_)->attributes
 #define Meter_name(this_)              As_Meter(this_)->name
 #define Meter_uiName(this_)            As_Meter(this_)->uiName
+#define Meter_maxItems(this_)          As_Meter(this_)->maxItems
 #define Meter_isMultiColumn(this_)     As_Meter(this_)->isMultiColumn
 #define Meter_isPercentChart(this_)    As_Meter(this_)->isPercentChart
 

rustedusted and others added 4 commits October 26, 2025 21:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Extension or improvement to existing feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Custom character for meter (instead of "|")

3 participants