mirror of
https://github.com/hyprwm/hyprland-plugins.git
synced 2024-11-25 03:35:59 +01:00
Hyprbars: Improve Title Rendering (#16)
* use pangocairo to draw title * add padding and ellipsis * add max and close colors to config * remove snake case, better config variable names * add pangocairo as a dependency to meson build * add `buttons:button_size`, adjust for bordersize * add button_size doc --------- Co-authored-by: nehrbash <stephen.nehrbass@infinitetactics.com>
This commit is contained in:
parent
274b46c1f7
commit
e80bf4a44d
5 changed files with 99 additions and 55 deletions
|
@ -1,4 +1,21 @@
|
|||
all:
|
||||
g++ -shared -fPIC --no-gnu-unique main.cpp barDeco.cpp -o hyprbars.so -g -I "/usr/include/pixman-1" -I "/usr/include/libdrm" $(shell pkg-config --cflags hyprland) -std=c++23
|
||||
CXX = g++
|
||||
CXXFLAGS = -shared -fPIC --no-gnu-unique -g -std=c++23
|
||||
INCLUDES = -I "/usr/include/pixman-1" -I "/usr/include/libdrm" -I $(shell pkg-config --cflags hyprland pangocairo)
|
||||
LIBS = $(shell pkg-config --libs pangocairo)
|
||||
|
||||
SRC = main.cpp barDeco.cpp
|
||||
TARGET = hyprbars.so
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(SRC)
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDES) $^ -o $@ $(LIBS)
|
||||
|
||||
clean:
|
||||
rm ./hyprbars.so
|
||||
rm ./$(TARGET)
|
||||
|
||||
meson-build:
|
||||
mkdir -p build
|
||||
cd build && meson .. && ninja
|
||||
|
||||
.PHONY: all meson-build clean
|
||||
|
|
|
@ -12,6 +12,9 @@ All config options are in `plugin:hyprbars`:
|
|||
plugin {
|
||||
hyprbars {
|
||||
# config
|
||||
buttons {
|
||||
# button config
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -20,8 +23,16 @@ plugin {
|
|||
|
||||
`bar_height` -> (int) bar's height (default 15)
|
||||
|
||||
`bar_text_color` -> (col) bar's title text color
|
||||
`col.text` -> (col) bar's title text color
|
||||
|
||||
`bar_text_size` -> (int) bar's title text font size (default 10)
|
||||
|
||||
`bar_text_font` -> (str) bar's title text font (default "Sans")
|
||||
|
||||
## Buttons Config
|
||||
|
||||
`button_size` -> (int) the size of the buttons.
|
||||
|
||||
`col.maximize` -> (col) maximize button color
|
||||
|
||||
`col.close` -> (col) close button color
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
#include <hyprland/src/Window.hpp>
|
||||
#include <pango/pangocairo.h>
|
||||
|
||||
#include "globals.hpp"
|
||||
|
||||
constexpr int BUTTONS_PAD = 5;
|
||||
constexpr int BUTTONS_SIZE = 10;
|
||||
constexpr int BUTTONS_ROUNDING = 5;
|
||||
|
||||
CHyprBar::CHyprBar(CWindow* pWindow) {
|
||||
m_pWindow = pWindow;
|
||||
|
@ -44,8 +43,9 @@ void CHyprBar::onMouseDown(wlr_pointer_button_event* e) {
|
|||
const auto COORDS = cursorRelativeToBar();
|
||||
|
||||
static auto* const PHEIGHT = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_height")->intValue;
|
||||
static auto* const PBORDERSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "general:border_size")->intValue;
|
||||
|
||||
if (!VECINRECT(COORDS, 0, 0, m_vLastWindowSize.x, *PHEIGHT)) {
|
||||
if (!VECINRECT(COORDS, 0, 0, m_vLastWindowSize.x + *PBORDERSIZE * 2, *PHEIGHT)) {
|
||||
|
||||
if (m_bDraggingThis) {
|
||||
g_pKeybindManager->m_mDispatchers["mouse"]("0movewindow");
|
||||
|
@ -69,22 +69,22 @@ void CHyprBar::onMouseDown(wlr_pointer_button_event* e) {
|
|||
}
|
||||
|
||||
// check if on a button
|
||||
static auto* const PBORDERSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "general:border_size")->intValue;
|
||||
static auto* const PBUTTONSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:buttons:button_size")->intValue;
|
||||
const auto BARBUF = Vector2D{(int)m_vLastWindowSize.x + 2 * *PBORDERSIZE, *PHEIGHT};
|
||||
Vector2D currentPos = Vector2D{BARBUF.x - BUTTONS_PAD - BUTTONS_SIZE, BARBUF.y / 2.0 - BUTTONS_SIZE / 2.0}.floor();
|
||||
Vector2D currentPos = Vector2D{BARBUF.x - BUTTONS_PAD - *PBUTTONSIZE, BARBUF.y / 2.0 - *PBUTTONSIZE / 2.0}.floor();
|
||||
currentPos.y -= BUTTONS_PAD / 2.0;
|
||||
|
||||
currentPos.x -= BUTTONS_PAD / 2.0;
|
||||
|
||||
if (VECINRECT(COORDS, currentPos.x, currentPos.y, currentPos.x + BUTTONS_SIZE + BUTTONS_PAD, currentPos.y + BUTTONS_SIZE + BUTTONS_PAD)) {
|
||||
if (VECINRECT(COORDS, currentPos.x, currentPos.y, currentPos.x + *PBUTTONSIZE + BUTTONS_PAD, currentPos.y + *PBUTTONSIZE + BUTTONS_PAD)) {
|
||||
// hit on close
|
||||
g_pCompositor->closeWindow(m_pWindow);
|
||||
return;
|
||||
}
|
||||
|
||||
currentPos.x -= BUTTONS_PAD + BUTTONS_SIZE;
|
||||
currentPos.x -= BUTTONS_PAD + *PBUTTONSIZE;
|
||||
|
||||
if (VECINRECT(COORDS, currentPos.x, currentPos.y, currentPos.x + BUTTONS_SIZE + BUTTONS_PAD, currentPos.y + BUTTONS_SIZE + BUTTONS_PAD)) {
|
||||
if (VECINRECT(COORDS, currentPos.x, currentPos.y, currentPos.x + *PBUTTONSIZE + BUTTONS_PAD, currentPos.y + *PBUTTONSIZE + BUTTONS_PAD)) {
|
||||
// hit on maximize
|
||||
g_pKeybindManager->m_mDispatchers["fullscreen"]("1");
|
||||
return;
|
||||
|
@ -94,8 +94,6 @@ void CHyprBar::onMouseDown(wlr_pointer_button_event* e) {
|
|||
}
|
||||
|
||||
void CHyprBar::onMouseMove(Vector2D coords) {
|
||||
static auto* const PHEIGHT = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_height")->intValue;
|
||||
|
||||
if (m_bDragPending) {
|
||||
m_bDragPending = false;
|
||||
g_pKeybindManager->m_mDispatchers["mouse"]("1movewindow");
|
||||
|
@ -108,32 +106,52 @@ void CHyprBar::onMouseMove(Vector2D coords) {
|
|||
}
|
||||
|
||||
void CHyprBar::renderBarTitle(const Vector2D& bufferSize) {
|
||||
static auto* const PCOLOR = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_text_color")->intValue;
|
||||
static auto* const PCOLOR = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:col.text")->intValue;
|
||||
static auto* const PSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_text_size")->intValue;
|
||||
static auto* const PFONT = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_text_font")->strValue;
|
||||
static auto* const PBUTTONSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:buttons:button_size")->intValue;
|
||||
static auto* const PBORDERSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "general:border_size")->intValue;
|
||||
|
||||
const CColor COLOR = *PCOLOR;
|
||||
|
||||
const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y);
|
||||
|
||||
const auto CAIRO = cairo_create(CAIROSURFACE);
|
||||
|
||||
const int BARPADDING = 10;
|
||||
|
||||
// clear the pixmap
|
||||
cairo_save(CAIRO);
|
||||
cairo_set_operator(CAIRO, CAIRO_OPERATOR_CLEAR);
|
||||
cairo_paint(CAIRO);
|
||||
cairo_restore(CAIRO);
|
||||
|
||||
// draw title
|
||||
cairo_select_font_face(CAIRO, PFONT->c_str(), CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
||||
cairo_set_font_size(CAIRO, *PSIZE);
|
||||
// draw title using Pango
|
||||
PangoLayout* layout = pango_cairo_create_layout(CAIRO);
|
||||
pango_layout_set_text(layout, m_szLastTitle.c_str(), -1);
|
||||
|
||||
PangoFontDescription* fontDesc = pango_font_description_from_string(PFONT->c_str());
|
||||
pango_font_description_set_size(fontDesc, *PSIZE * PANGO_SCALE);
|
||||
pango_layout_set_font_description(layout, fontDesc);
|
||||
pango_font_description_free(fontDesc);
|
||||
|
||||
const int leftPadding = *PBORDERSIZE + BARPADDING;
|
||||
const int rightPadding = (*PBUTTONSIZE * 2) + (BUTTONS_PAD * 3) + *PBORDERSIZE + BARPADDING;
|
||||
const int maxWidth = bufferSize.x - leftPadding - rightPadding;
|
||||
|
||||
pango_layout_set_width(layout, maxWidth * PANGO_SCALE);
|
||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
|
||||
|
||||
cairo_set_source_rgba(CAIRO, COLOR.r, COLOR.g, COLOR.b, COLOR.a);
|
||||
|
||||
cairo_text_extents_t cairoExtents;
|
||||
cairo_text_extents(CAIRO, m_szLastTitle.c_str(), &cairoExtents);
|
||||
int layoutWidth, layoutHeight;
|
||||
pango_layout_get_size(layout, &layoutWidth, &layoutHeight);
|
||||
const int xOffset = std::round(((bufferSize.x - *PBORDERSIZE) / 2.0 - layoutWidth / PANGO_SCALE / 2.0));
|
||||
const int yOffset = std::round((bufferSize.y / 2.0 - layoutHeight / PANGO_SCALE / 2.0));
|
||||
|
||||
cairo_move_to(CAIRO, std::round(bufferSize.x / 2.0 - cairoExtents.width / 2.0), *PSIZE + std::round(bufferSize.y / 2.0 - cairoExtents.height / 2.0));
|
||||
cairo_show_text(CAIRO, m_szLastTitle.c_str());
|
||||
cairo_move_to(CAIRO, xOffset, yOffset);
|
||||
pango_cairo_show_layout(CAIRO, layout);
|
||||
|
||||
g_object_unref(layout);
|
||||
|
||||
cairo_surface_flush(CAIROSURFACE);
|
||||
|
||||
|
@ -157,6 +175,9 @@ void CHyprBar::renderBarTitle(const Vector2D& bufferSize) {
|
|||
}
|
||||
|
||||
void CHyprBar::renderBarButtons(const Vector2D& bufferSize) {
|
||||
static auto* const PCLOSECOLOR = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:buttons:col.close")->intValue;
|
||||
static auto* const PMAXCOLOR = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:buttons:col.maximize")->intValue;
|
||||
static auto* const PBUTTONSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:buttons:button_size")->intValue;
|
||||
|
||||
const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y);
|
||||
const auto CAIRO = cairo_create(CAIROSURFACE);
|
||||
|
@ -172,30 +193,20 @@ void CHyprBar::renderBarButtons(const Vector2D& bufferSize) {
|
|||
auto drawButton = [&](Vector2D pos, CColor col) -> void {
|
||||
const int X = pos.x;
|
||||
const int Y = pos.y;
|
||||
const int WIDTH = BUTTONS_SIZE;
|
||||
const int HEIGHT = BUTTONS_SIZE;
|
||||
const int RADIUS = BUTTONS_ROUNDING;
|
||||
constexpr double DEGREES = M_PI / 180.0;
|
||||
const int RADIUS = static_cast<int>(std::ceil(*PBUTTONSIZE / 2.0));
|
||||
|
||||
cairo_set_source_rgba(CAIRO, col.r, col.g, col.b, col.a);
|
||||
|
||||
cairo_new_sub_path(CAIRO);
|
||||
cairo_arc(CAIRO, X + WIDTH - RADIUS, Y + RADIUS, RADIUS, -90 * DEGREES, 0 * DEGREES);
|
||||
cairo_arc(CAIRO, X + WIDTH - RADIUS, Y + HEIGHT - RADIUS, RADIUS, 0 * DEGREES, 90 * DEGREES);
|
||||
cairo_arc(CAIRO, X + RADIUS, Y + HEIGHT - RADIUS, RADIUS, 90 * DEGREES, 180 * DEGREES);
|
||||
cairo_arc(CAIRO, X + RADIUS, Y + RADIUS, RADIUS, 180 * DEGREES, 270 * DEGREES);
|
||||
cairo_close_path(CAIRO);
|
||||
|
||||
cairo_fill_preserve(CAIRO);
|
||||
cairo_arc(CAIRO, X, Y + RADIUS, RADIUS, 0, 2 * M_PI);
|
||||
cairo_fill(CAIRO);
|
||||
};
|
||||
|
||||
Vector2D currentPos = Vector2D{bufferSize.x - BUTTONS_PAD - BUTTONS_SIZE, bufferSize.y / 2.0 - BUTTONS_SIZE / 2.0}.floor();
|
||||
Vector2D currentPos = Vector2D{bufferSize.x - BUTTONS_PAD - *PBUTTONSIZE, bufferSize.y / 2.0 - *PBUTTONSIZE / 2.0}.floor();
|
||||
|
||||
drawButton(currentPos, CColor(1.0, 0.0, 0.0, 0.8));
|
||||
drawButton(currentPos, CColor(*PCLOSECOLOR));
|
||||
|
||||
currentPos.x -= BUTTONS_PAD + BUTTONS_SIZE;
|
||||
currentPos.x -= BUTTONS_PAD + *PBUTTONSIZE;
|
||||
|
||||
drawButton(currentPos, CColor(0.9, 0.9, 0.1, 0.8));
|
||||
drawButton(currentPos, CColor(*PMAXCOLOR));
|
||||
|
||||
// copy the data to an OpenGL texture we have
|
||||
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
|
||||
|
@ -239,8 +250,8 @@ void CHyprBar::draw(CMonitor* pMonitor, float a, const Vector2D& offset) {
|
|||
|
||||
const auto BARBUF = Vector2D{(int)m_vLastWindowSize.x + 2 * *PBORDERSIZE, *PHEIGHT} * pMonitor->scale;
|
||||
|
||||
wlr_box titleBarBox = {(int)m_vLastWindowPos.x - *PBORDERSIZE - pMonitor->vecPosition.x, (int)m_vLastWindowPos.y - *PHEIGHT - pMonitor->vecPosition.y,
|
||||
(int)m_vLastWindowSize.x + 2 * *PBORDERSIZE, *PHEIGHT + *PROUNDING * 2 /* to fill the bottom cuz we can't disable rounding there */};
|
||||
wlr_box titleBarBox = {(int)m_vLastWindowPos.x - *PBORDERSIZE - pMonitor->vecPosition.x, (int)m_vLastWindowPos.y - *PBORDERSIZE - *PHEIGHT - pMonitor->vecPosition.y,
|
||||
(int)m_vLastWindowSize.x + 2 * *PBORDERSIZE, *PHEIGHT + *PROUNDING * 3 /* to fill the bottom cuz we can't disable rounding there */};
|
||||
|
||||
titleBarBox.x += offset.x;
|
||||
titleBarBox.y += offset.y;
|
||||
|
@ -329,5 +340,6 @@ SWindowDecorationExtents CHyprBar::getWindowDecorationReservedArea() {
|
|||
|
||||
Vector2D CHyprBar::cursorRelativeToBar() {
|
||||
static auto* const PHEIGHT = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_height")->intValue;
|
||||
return g_pInputManager->getMouseCoordsInternal() - m_pWindow->m_vRealPosition.vec() + Vector2D{0, *PHEIGHT};
|
||||
static auto* const PBORDER = &HyprlandAPI::getConfigValue(PHANDLE, "general:border_size")->intValue;
|
||||
return g_pInputManager->getMouseCoordsInternal() - m_pWindow->m_vRealPosition.vec() + Vector2D{*PBORDER, *PHEIGHT + *PBORDER};
|
||||
}
|
|
@ -29,9 +29,12 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
|||
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprbars:bar_color", SConfigValue{.intValue = configStringToInt("rgba(33333388)")});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprbars:bar_height", SConfigValue{.intValue = 15});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprbars:bar_text_color", SConfigValue{.intValue = configStringToInt("rgba(ffffffff)")});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprbars:col.text", SConfigValue{.intValue = configStringToInt("rgba(ffffffff)")});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprbars:bar_text_size", SConfigValue{.intValue = 10});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprbars:bar_text_font", SConfigValue{.strValue = "Sans"});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprbars:buttons:col.close", SConfigValue{.intValue = configStringToInt("rgba(cc0000cc)")});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprbars:buttons:col.maximize", SConfigValue{.intValue = configStringToInt("rgba(ffff33cc)")});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprbars:buttons:button_size", SConfigValue{.intValue = 10});
|
||||
|
||||
// add deco to existing windows
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
|
|
|
@ -22,6 +22,7 @@ shared_module(meson.project_name(), src,
|
|||
dependency('hyprland'),
|
||||
dependency('pixman-1'),
|
||||
dependency('libdrm'),
|
||||
dependency('pangocairo')
|
||||
],
|
||||
install: true,
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue