fix: Make sure clickable areas are aligned properly

- Avoid odd glyph width's for center-aligned text
since it breaks the positioning of clickable area's

- Added visual hints for clickable areas for debugging
This commit is contained in:
Michael Carlberg 2016-10-11 03:01:12 +02:00
parent b4b563dda6
commit 20350e5fe6
4 changed files with 93 additions and 37 deletions

View File

@ -18,6 +18,8 @@
#include <thread>
#include <vector>
#include "config.hpp"
#define LEMONBUDDY_NS \
namespace lemonbuddy { \
inline namespace v2_0_0 {

View File

@ -425,6 +425,13 @@ class bar : public xpp::event::sink<evt::button_press> {
m_bar.align = alignment::LEFT;
m_xpos = m_borders[border::LEFT].size;
m_attributes = 0;
#if DEBUG and DRAW_CLICKABLE_AREA_HINTS
for (auto&& action : m_actions) {
m_connection.destroy_window(action.clickable_area);
}
#endif
m_actions.clear();
draw_background();
@ -465,6 +472,14 @@ class bar : public xpp::event::sink<evt::button_press> {
m_connection.copy_area(
m_pixmap, m_window, m_gcontexts.at(gc::BR), 0, 0, 0, 0, m_bar.width, m_bar.height);
#if DEBUG and DRAW_CLICKABLE_AREA_HINTS
map<alignment, int> hint_num{
{ {alignment::LEFT, 0},
{alignment::CENTER, 0},
{alignment::RIGHT, 0},
}};
#endif
for (auto&& action : m_actions) {
if (action.active) {
m_log.warn("Action block not closed");
@ -475,6 +490,29 @@ class bar : public xpp::event::sink<evt::button_press> {
m_log.trace("action.mousebtn = %i", static_cast<int>(action.mousebtn));
m_log.trace("action.start_x = %i", action.start_x);
m_log.trace("action.end_x = %i", action.end_x);
#if DEBUG and DRAW_CLICKABLE_AREA_HINTS
m_log.info("Drawing clickable area hints");
hint_num[action.align]++;
auto x = action.start_x;
auto y = m_bar.y + hint_num[action.align]++ * DRAW_CLICKABLE_AREA_HINTS_OFFSET_Y;
auto w = action.end_x - action.start_x - 2;
auto h = m_bar.height - 2;
const uint32_t mask = XCB_CW_BORDER_PIXEL | XCB_CW_OVERRIDE_REDIRECT;
const uint32_t border_color = hint_num[action.align] % 2 ? 0xff0000 : 0x00ff00;
const uint32_t values[2]{border_color, true};
auto scr = m_connection.screen();
action.clickable_area = m_connection.generate_id();
m_connection.create_window_checked(scr->root_depth, action.clickable_area, scr->root, x, y,
w, h, 1, XCB_WINDOW_CLASS_INPUT_OUTPUT, scr->root_visual, mask, values);
m_connection.map_window_checked(action.clickable_area);
#else
m_log.trace("bar: Visual hints for clickable area's disabled");
#endif
}
}
} //}}}
@ -600,8 +638,7 @@ class bar : public xpp::event::sink<evt::button_press> {
action.align = m_bar.align;
action.mousebtn = btn;
action.start_x = m_xpos;
action.command = cmd;
action.command = string_util::replace_all(action.command, ":", "\\:");
action.command = string_util::replace_all(cmd, ":", "\\:");
m_actions.emplace_back(action);
} //}}}
@ -610,29 +647,33 @@ class bar : public xpp::event::sink<evt::button_press> {
*/
void on_action_block_close(mousebtn btn) { //{{{
m_log.trace("bar: action_block_close(%i)", static_cast<int>(btn));
auto n_actions = m_actions.size();
while (n_actions--) {
action_block& action = m_actions[n_actions];
for (auto i = m_actions.size(); i > 0; i--) {
auto& action = m_actions[i - 1];
if (!action.active || action.mousebtn != btn)
continue;
action.end_x = m_xpos;
action.active = false;
if (action.align == alignment::CENTER) {
auto width = action.end_x - action.start_x;
auto center = m_bar.width / 2;
auto x1 = center - width / 2;
auto x2 = center + width / 2;
action.start_x = x1;
action.end_x = x2;
if (action.align == alignment::LEFT) {
action.end_x = m_xpos;
} else if (action.align == alignment::CENTER) {
int base_x = m_bar.width;
base_x -= m_borders[border::RIGHT].size;
base_x /= 2;
base_x += m_borders[border::LEFT].size;
int clickable_width = m_xpos - action.start_x;
action.start_x = base_x - clickable_width / 2 + action.start_x / 2;
action.end_x = action.start_x + clickable_width;
} else if (action.align == alignment::RIGHT) {
auto x1 = m_bar.width - action.end_x;
auto x2 = m_bar.width - action.start_x;
action.start_x = x1;
action.end_x = x2;
int base_x = m_bar.width - m_borders[border::RIGHT].size;
action.start_x = base_x - m_xpos + action.start_x;
action.end_x = base_x;
}
return;
}
} //}}}
@ -759,36 +800,33 @@ class bar : public xpp::event::sink<evt::button_press> {
* Shift the contents of the pixmap horizontally
*/
int draw_shift(int x, int chr_width) { //{{{
int delta = 0;
int delta = chr_width;
switch (m_bar.align) {
case alignment::CENTER:
m_connection.copy_area(m_pixmap, m_pixmap, m_gcontexts.at(gc::FG), m_bar.width / 2 - x / 2,
0, m_bar.width / 2 - (x + chr_width) / 2, 0, x, m_bar.height);
x = m_bar.width / 2 - (x + chr_width) / 2 + x;
delta = chr_width / 2;
break;
case alignment::RIGHT:
m_connection.copy_area(m_pixmap, m_pixmap, m_gcontexts.at(gc::FG), m_bar.width - x, 0,
m_bar.width - x - chr_width, 0, x, m_bar.height);
x = m_bar.width - chr_width - m_borders[border::RIGHT].size;
delta = chr_width;
break;
default:
break;
if (m_bar.align == alignment::CENTER) {
int base_x = m_bar.width;
base_x -= m_borders[border::RIGHT].size;
base_x /= 2;
base_x += m_borders[border::LEFT].size;
m_connection.copy_area(m_pixmap, m_pixmap, m_gcontexts.at(gc::FG), base_x - x / 2, 0,
base_x - (x + chr_width) / 2, 0, x, m_bar.height);
x = base_x - (x + chr_width) / 2 + x;
delta /= 2;
} else if (m_bar.align == alignment::RIGHT) {
m_connection.copy_area(m_pixmap, m_pixmap, m_gcontexts.at(gc::FG), m_bar.width - x, 0,
m_bar.width - x - chr_width, 0, x, m_bar.height);
x = m_bar.width - chr_width - m_borders[border::RIGHT].size;
}
draw_util::fill(m_connection, m_pixmap, m_gcontexts.at(gc::BG), x, 0, chr_width, m_bar.height);
if (delta != 0 && !m_actions.empty()) {
// Translate pos of clickable areas
if (m_bar.align != alignment::LEFT)
for (auto&& action : m_actions) {
if (action.active || action.align != m_bar.align)
continue;
action.start_x -= delta;
action.end_x -= delta;
}
}
return x;
} //}}}
@ -801,7 +839,7 @@ class bar : public xpp::event::sink<evt::button_press> {
auto& font = m_fontmanager->match_char(character);
if (!font) {
// m_log.warn("No suitable font found");
m_log.warn("No suitable font found for character at index %i", character);
return;
}
@ -813,6 +851,11 @@ class bar : public xpp::event::sink<evt::button_press> {
// TODO: cache
auto chr_width = m_fontmanager->char_width(font, character);
// Avoid odd glyph width's for center-aligned text
// since it breaks the positioning of clickable area's
if (m_bar.align == alignment::CENTER && chr_width % 2)
chr_width++;
auto x = draw_shift(m_xpos, chr_width);
auto y = m_bar.vertical_mid + font->height / 2 - font->descent + font->offset_y;

View File

@ -96,6 +96,9 @@ struct action_block {
int16_t end_x{0};
alignment align;
bool active{true};
#if DEBUG and DRAW_CLICKABLE_AREA_HINTS
xcb_window_t clickable_area;
#endif
};
LEMONBUDDY_NS_END

View File

@ -16,6 +16,14 @@
#cmakedefine DISABLE_TRAY
#cmakedefine DISABLE_DRAW
#ifdef DEBUG
#cmakedefine01 DRAW_CLICKABLE_AREA_HINTS
#cmakedefine DRAW_CLICKABLE_AREA_HINTS_OFFSET_Y @DRAW_CLICKABLE_AREA_HINTS_OFFSET_Y@
#ifndef DRAW_CLICKABLE_AREA_HINTS_OFFSET_Y
#define DRAW_CLICKABLE_AREA_HINTS_OFFSET_Y 0
#endif
#endif
#define BUILDER_SPACE_TOKEN "%__"
#define ALSA_SOUNDCARD "@SETTING_ALSA_SOUNDCARD@"
#define CONNECTION_TEST_IP "@SETTING_CONNECTION_TEST_IP@"