Skip to content

Conversation

@pazam-h2
Copy link

@pazam-h2 pazam-h2 commented Jul 1, 2025

This PR adds a visual category selector to the Hotkeys settings dialog, allowing users to filter hotkeys by category.
The category names are displayed in a 2-line layout above the hotkey list. Selecting a category filters the list accordingly.

EDIT 1: the placement of the categories have been changed to be on the left side as an organized list.

EDIT 2: added an 'All' button to have the hotkeys list unfiltered.

EDIT 3: added Category sub-title

from:
image

To:
image

Closes #9940

@pazam-h2

This comment was marked as outdated.

@ihhub
Copy link
Owner

ihhub commented Jul 2, 2025

Hi @pazam-h2 , this implementation contradicts the overall UX design of the game: none of text elements are clickable. An ideal solution it to embed these categories into the list itself.

@pazam-h2
Copy link
Author

pazam-h2 commented Jul 2, 2025

Changed from text elements to just a list.
Image updated on opening post.

@zenseii zenseii added improvement New feature, request or improvement ui UI/GUI related stuff labels Jul 6, 2025
@zenseii zenseii added this to the 1.1.10 milestone Jul 6, 2025
@ihhub ihhub modified the milestones: 1.1.10, 1.1.11 Jul 20, 2025
@ihhub
Copy link
Owner

ihhub commented Jul 27, 2025

Hi @pazam-h2 , could you please provide a screenshot of the window for the original 640x480 resolution?

Copy link
Owner

@ihhub ihhub left a comment

Choose a reason for hiding this comment

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

Hi @pazam-h2 , I added several comments in this pull request. Could you please take a look?

enum class HotKeyCategory : uint8_t
enum class HotKeyCategory : int
{
ALL = -1,
Copy link
Owner

Choose a reason for hiding this comment

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

Please revert this change. This seem like a hack rather than a solution. Usually, all items in enumeration start from 0 (default value). We call simply call Game::getAllHotKeyEvents(); for that particular entry in the dialog.

const char * Game::getHotKeyCategoryName( const HotKeyCategory category )
{
switch ( category ) {
case HotKeyCategory::ALL:
Copy link
Owner

Choose a reason for hiding this comment

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

Please revert this change. This doesn't belong to the class but only for a single specific dialog. So, let's make changes where they needed - in that dialog.

Comment on lines +270 to +276
std::set<Game::HotKeyCategory> seen;
for ( const auto & pair : hotKeyEvents ) {
if ( seen.find( pair.second ) == seen.end() ) {
seen.insert( pair.second );
uniqueCategories.push_back( pair.second );
}
}
Copy link
Owner

Choose a reason for hiding this comment

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

This code isn't needed. We can directly take all entries from the enumeration.

Comment on lines -293 to -294
std::vector<std::pair<Game::HotKeyEvent, Game::HotKeyCategory>> hotKeyEvents = Game::getAllHotKeyEvents();

Copy link
Owner

Choose a reason for hiding this comment

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

With the above comment we can revert this change since hotKeyEvents is not being used above.

const fheroes2::Text categoryHeader( _( "Category:" ), fheroes2::FontType::normalWhite() );
categoryHeader.draw( roi.x + 45, roi.y + 32, display );

for ( const Game::HotKeyCategory category : uniqueCategories ) {
Copy link
Owner

Choose a reason for hiding this comment

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

We don't need uniqueCategories but directly use enumeration entries. Just add one more entry before the loop for _( All ).

Comment on lines +296 to +305
const bool isSelected = ( category == selectedCategory );
const fheroes2::FontType fontType = isSelected ? fheroes2::FontType::normalYellow() : fheroes2::FontType::normalWhite();
const fheroes2::Text categoryText( _( Game::getHotKeyCategoryName( category ) ), fontType );
categoryText.draw( categoryRoi.x + 4, categoryOffsetY, display );

const fheroes2::Rect textRect( categoryRoi.x, categoryOffsetY, categoryRoi.width, categoryText.height() + 4 );
categoryRects.emplace_back( category, textRect );

categoryOffsetY += categoryText.height() + 4;
}
Copy link
Owner

Choose a reason for hiding this comment

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

Please move this code into a separate function in anonymous namespace and call it here and in the code below to avoid code duplication.


display.render( background.totalArea() );

std::vector<std::pair<Game::HotKeyEvent, Game::HotKeyCategory>> filtered = hotKeyEvents;
Copy link
Owner

Choose a reason for hiding this comment

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

This variable is not needed especially outside the loop. Its lifetime is within the newly created below if-condition body.

listbox.QueueEventProcessing();

for ( const auto & pair : categoryRects ) {
if ( le.MouseClickLeft( pair.second ) ) {
Copy link
Owner

Choose a reason for hiding this comment

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

We should update the list only when clicking is done on a different item. Now we rebuild everything without this conditon.

Comment on lines +355 to +363
for ( auto & categoryPair : categoryRects ) {
const bool isSelected = ( categoryPair.first == selectedCategory );
const fheroes2::FontType fontType = isSelected ? fheroes2::FontType::normalYellow() : fheroes2::FontType::normalWhite();
const fheroes2::Text categoryText( _( Game::getHotKeyCategoryName( categoryPair.first ) ), fontType );
categoryText.draw( categoryRoi.x + 4, categoryOffsetY, display );

categoryPair.second = { categoryRoi.x, categoryOffsetY, categoryRoi.width, categoryText.height() + 4 };
categoryOffsetY += categoryText.height() + 4;
}
Copy link
Owner

Choose a reason for hiding this comment

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

I would like to see how this dialog looks in the original resolution: 640x480 and whether every element fits. Also, please attach screenshots in other languages to see how it looks and whether the dialog is not being crumped for some languages.

#include <cassert>
#include <cstdint>
#include <memory>
#include <set>
Copy link
Owner

Choose a reason for hiding this comment

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

This header won't be needed with the changes proposed below.

@ihhub ihhub marked this pull request as draft July 29, 2025 11:45
@ihhub
Copy link
Owner

ihhub commented Aug 30, 2025

I don't think that this is a good design solution for the original resolution:

image

@ihhub ihhub modified the milestones: 1.1.11, 1.1.12 Sep 14, 2025
@ihhub ihhub modified the milestones: 1.1.12, 1.1.13 Nov 9, 2025
@ihhub ihhub modified the milestones: 1.1.13, 1.2.0 Dec 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement New feature, request or improvement ui UI/GUI related stuff

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Categories in the Hotkey Options Screen

3 participants