4K Monitors and Toolbar Icons

Running head long into this issue again. I really don’t want to change all my icons to SVG and PDF at this time, its not an easy process and the end result isn’t very pretty I’ve already tried a few times.

I’ve been trying to figure out an alternative workaround for now. Is there a way to determine if a computer is using a 4k monitor (resolution)?

Just an idea:

# corner (index) ⇒ Array(Integer, Integer)

If you check the 3rd corner (bottom right)

#Dirty
s_width, s_height = Sketchup.active_model.active_view.corner(3)
high_res = s_width > 1920 ? true : false
#OR:
#high_res =s_height  > 1080 ? true : false

Unfortunately it will give unexpected result if the window is not maximised…

No, you need to ask the precise question… You do not want to know whether the resolution of the display is 4K, but whether the UI is scaled. That means whether the user expects (and needs) your UI (in SketchUp only toolbar/cursor icons and OpenGL drawing) to be scaled. Don’t conclude just from the display resolution that the user wants the UI to be scaled to a factor that you determine.

Therefore SketchUp 2017+ responds to a method UI.scale_factor.

But you don’t really need this for toolbar icons (and if you can avoid extra code paths/switches, you should). If you just upsample your toolbar icons in a batch image editor by a factor of 2 (nearest neighbor method), they display fine and readable (although a little pixelated).

3 Likes

I tried this already.

I took some of my 24x24 icons and changed the pixel size to 48x48 (cubic nearest neighbor or something like that). The images don’t look all that bad.

However, when I load them up in SU at normal resolution (1080p) the icons show up a bit too big. They might render just fine in a 4k setting but at normal resolutions it looks like garbage.

What SketchUp version? Is your normal resolution 100% / scale_factor=1 ?

This inconsistency came up when SketchUp’s designers once added a “soft” guideline to make the UI less cluttered through more whitespace (like many modern websites and other UIs). However the UI toolkit that SketchUp uses did not allow to programmatically enforce a padding, so they increased the button size and instructed developers to use the exact icon size (then smaller than the button) to achieve space for the padding. Previously developers were already using larger icons because they would just fill up all available button space and thus scale with the UI scale.

Rules which are never enforced (or have no noticeable effect) will be broken.
Especially when the rule is introduced after other common practice is already in use.

What you can do:

  • Icon images (according to the API: small=16px, large=24px) are actually displayed centered within 24px / 32px buttons. To enforce padding, you can enlarge the image canvas to 24px/32px (with transparent background) to make the icons actually fill the whole button.
    If you then upscale the images to 48px/64px for hi-dpi, the UI toolkit squeezes them for low-dpi settings into the button size but the colored image area will not be bigger than 16px/24px.
1 Like

it’s common to include three image formats and use conditionals…

I use this sort of thing…

    path = File.dirname(__FILE__)

    # to handle the file formats for toolbar images...
    ext = '.png'

    if Sketchup.version.to_i >= 16
      ext = OSX ? '.pdf' : '.svg'
    end

    name  = NAME.sub('jcb_', '')
    title = TITLE
    # create toolbar
    tb = UI::Toolbar.new(title)
    # menu item
    menu = UI.menu('Plugins', title)

    # add a cmd for menu, toolbar or shortcut item...
    cmd = UI::Command.new(title) do
      # use load for testing locally and require for production without...
      if ENV['LOGNAME'] == 'johns_iMac' # for dev...
        load File.join(path, "#{name}_logic.rb")
      else
        require File.join(path, "#{name}_logic")
      end
      # this method becomes available on load as it's defined under the same namespace...
      user_input
    end

    cmd.tooltip = cmd.status_bar_text = TRANSL8['menu_message'] + '...'

    cmd.large_icon = cmd.small_icon = File.join(path, 'Resources', 'images', "#{name}#{ext}")

john

1 Like

Or hide the ifs in a refactored-out method like get_image_resource_path:

Here I assign the path returned from this method to both small and large icon (as thomthom and the DevCamp presentations recommend now).

Also a good example (regarding the version/feature detection discussion) where I only fall back to a version switch because I cannot detect the new svg image support.

(By the way, kudos to the github-onebox, given a link to a single line it determined the exact range of lines that I wanted to link to.)

2 Likes

I’m going to give this method a shot. I’ve handed the updated toolbar off to one of my clients who is running 4k, we will see how well it works.

With the extra padding I’m able to get my proper look back with the 48px/64px icons. Thank-you for the informative explanation.

P.S. Looks like it works on Windows 10 running 4k, I’m assuming it will also work with a Mac running 4k, but I have no way to know until someone tries it out.