diff a/x.c b/x.c (rejected hunks) @@ -1461,8 +1514,357 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i /* Render underline and strikethrough. */ if (base.mode & ATTR_UNDERLINE) { - XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, - width, 1); // Underline Color const int widthThreshold = 28; // +1 width every widthThreshold px of font int wlw = (win.ch / widthThreshold) + 1; // Wave Line Width int linecolor; if ((base.ucolor[0] >= 0) && !(base.mode & ATTR_BLINK && win.mode & MODE_BLINK) && !(base.mode & ATTR_INVISIBLE) ) { // Special color for underline // Index if (base.ucolor[1] < 0) { linecolor = dc.col[base.ucolor[0]].pixel; } // RGB else { XColor lcolor; lcolor.red = base.ucolor[0] * 257; lcolor.green = base.ucolor[1] * 257; lcolor.blue = base.ucolor[2] * 257; lcolor.flags = DoRed | DoGreen | DoBlue; XAllocColor(xw.dpy, xw.cmap, &lcolor); linecolor = lcolor.pixel; } } else { // Foreground color for underline linecolor = fg->pixel; } XGCValues ugcv = { .foreground = linecolor, .line_width = wlw, .line_style = LineSolid, .cap_style = CapNotLast }; GC ugc = XCreateGC(xw.dpy, XftDrawDrawable(xw.draw), GCForeground | GCLineWidth | GCLineStyle | GCCapStyle, &ugcv); // Underline Style if (base.ustyle != 3) { //XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, width, 1); XFillRectangle(xw.dpy, XftDrawDrawable(xw.draw), ugc, winx, winy + dc.font.ascent + 1, width, wlw); } else if (base.ustyle == 3) { int ww = win.cw;//width; int wh = dc.font.descent - wlw/2 - 1;//r.height/7; int wx = winx; int wy = winy + win.ch - dc.font.descent; #if UNDERCURL_STYLE == UNDERCURL_CURLY // Draw waves int narcs = charlen * 2 + 1; XArc *arcs = xmalloc(sizeof(XArc) * narcs); int i = 0; for (i = 0; i < charlen-1; i++) { arcs[i*2] = (XArc) { .x = wx + win.cw * i + ww / 4, .y = wy, .width = win.cw / 2, .height = wh, .angle1 = 0, .angle2 = 180 * 64 }; arcs[i*2+1] = (XArc) { .x = wx + win.cw * i + ww * 0.75, .y = wy, .width = win.cw/2, .height = wh, .angle1 = 180 * 64, .angle2 = 180 * 64 }; } // Last wave arcs[i*2] = (XArc) {wx + ww * i + ww / 4, wy, ww / 2, wh, 0, 180 * 64 }; // Last wave tail arcs[i*2+1] = (XArc) {wx + ww * i + ww * 0.75, wy, ceil(ww / 2.), wh, 180 * 64, 90 * 64}; // First wave tail i++; arcs[i*2] = (XArc) {wx - ww/4 - 1, wy, ceil(ww / 2.), wh, 270 * 64, 90 * 64 }; XDrawArcs(xw.dpy, XftDrawDrawable(xw.draw), ugc, arcs, narcs); free(arcs); #elif UNDERCURL_STYLE == UNDERCURL_SPIKY // Make the underline corridor larger /* wy -= wh; */ wh *= 2; // Set the angle of the slope to 45° ww = wh; // Position of wave is independent of word, it's absolute wx = (wx / (ww/2)) * (ww/2); int marginStart = winx - wx; // Calculate number of points with floating precision float n = width; // Width of word in pixels n = (n / ww) * 2; // Number of slopes (/ or \) n += 2; // Add two last points int npoints = n; // Convert to int // Total length of underline float waveLength = 0; if (npoints >= 3) { // We add an aditional slot in case we use a bonus point XPoint *points = xmalloc(sizeof(XPoint) * (npoints + 1)); // First point (Starts with the word bounds) points[0] = (XPoint) { .x = wx + marginStart, .y = (isSlopeRising(wx, 0, ww)) ? (wy - marginStart + ww/2.f) : (wy + marginStart) }; // Second point (Goes back to the absolute point coordinates) points[1] = (XPoint) { .x = (ww/2.f) - marginStart, .y = (isSlopeRising(wx, 1, ww)) ? (ww/2.f - marginStart) : (-ww/2.f + marginStart) }; waveLength += (ww/2.f) - marginStart; // The rest of the points for (int i = 2; i < npoints-1; i++) { points[i] = (XPoint) { .x = ww/2, .y = (isSlopeRising(wx, i, ww)) ? wh/2 : -wh/2 }; waveLength += ww/2; } // Last point points[npoints-1] = (XPoint) { .x = ww/2, .y = (isSlopeRising(wx, npoints-1, ww)) ? wh/2 : -wh/2 }; waveLength += ww/2; // End if (waveLength < width) { // Add a bonus point? int marginEnd = width - waveLength; points[npoints] = (XPoint) { .x = marginEnd, .y = (isSlopeRising(wx, npoints, ww)) ? (marginEnd) : (-marginEnd) }; npoints++; } else if (waveLength > width) { // Is last point too far? int marginEnd = waveLength - width; points[npoints-1].x -= marginEnd; if (isSlopeRising(wx, npoints-1, ww)) points[npoints-1].y -= (marginEnd); else points[npoints-1].y += (marginEnd); } // Draw the lines XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, npoints, CoordModePrevious); // Draw a second underline with an offset of 1 pixel if ( ((win.ch / (widthThreshold/2)) % 2)) { points[0].x++; XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, npoints, CoordModePrevious); } // Free resources free(points); } #else // UNDERCURL_CAPPED // Cap is half of wave width float capRatio = 0.5f; // Make the underline corridor larger wh *= 2; // Set the angle of the slope to 45° ww = wh; ww *= 1 + capRatio; // Add a bit of width for the cap // Position of wave is independent of word, it's absolute wx = (wx / ww) * ww; float marginStart; switch(getSlope(winx, 0, ww)) { case UNDERCURL_SLOPE_ASCENDING: marginStart = winx - wx; break; case UNDERCURL_SLOPE_TOP_CAP: marginStart = winx - (wx + (ww * (2.f/6.f))); break; case UNDERCURL_SLOPE_DESCENDING: marginStart = winx - (wx + (ww * (3.f/6.f))); break; case UNDERCURL_SLOPE_BOTTOM_CAP: marginStart = winx - (wx + (ww * (5.f/6.f))); break; } // Calculate number of points with floating precision float n = width; // Width of word in pixels // ._. n = (n / ww) * 4; // Number of points (./ \.) n += 2; // Add two last points int npoints = n; // Convert to int // Position of the pen to draw the lines float penX = 0; float penY = 0; if (npoints >= 3) { XPoint *points = xmalloc(sizeof(XPoint) * (npoints + 1)); // First point (Starts with the word bounds) penX = winx; switch (getSlope(winx, 0, ww)) { case UNDERCURL_SLOPE_ASCENDING: penY = wy + wh/2.f - marginStart; break; case UNDERCURL_SLOPE_TOP_CAP: penY = wy; break; case UNDERCURL_SLOPE_DESCENDING: penY = wy + marginStart; break; case UNDERCURL_SLOPE_BOTTOM_CAP: penY = wy + wh/2.f; break; } points[0].x = penX; points[0].y = penY; // Second point (Goes back to the absolute point coordinates) switch (getSlope(winx, 1, ww)) { case UNDERCURL_SLOPE_ASCENDING: penX += ww * (1.f/6.f) - marginStart; penY += 0; break; case UNDERCURL_SLOPE_TOP_CAP: penX += ww * (2.f/6.f) - marginStart; penY += -wh/2.f + marginStart; break; case UNDERCURL_SLOPE_DESCENDING: penX += ww * (1.f/6.f) - marginStart; penY += 0; break; case UNDERCURL_SLOPE_BOTTOM_CAP: penX += ww * (2.f/6.f) - marginStart; penY += -marginStart + wh/2.f; break; } points[1].x = penX; points[1].y = penY; // The rest of the points for (int i = 2; i < npoints; i++) { switch (getSlope(winx, i, ww)) { case UNDERCURL_SLOPE_ASCENDING: case UNDERCURL_SLOPE_DESCENDING: penX += ww * (1.f/6.f); penY += 0; break; case UNDERCURL_SLOPE_TOP_CAP: penX += ww * (2.f/6.f); penY += -wh / 2.f; break; case UNDERCURL_SLOPE_BOTTOM_CAP: penX += ww * (2.f/6.f); penY += wh / 2.f; break; } points[i].x = penX; points[i].y = penY; } // End float waveLength = penX - winx; if (waveLength < width) { // Add a bonus point? int marginEnd = width - waveLength; penX += marginEnd; switch(getSlope(winx, npoints, ww)) { case UNDERCURL_SLOPE_ASCENDING: case UNDERCURL_SLOPE_DESCENDING: //penY += 0; break; case UNDERCURL_SLOPE_TOP_CAP: penY += -marginEnd; break; case UNDERCURL_SLOPE_BOTTOM_CAP: penY += marginEnd; break; } points[npoints].x = penX; points[npoints].y = penY; npoints++; } else if (waveLength > width) { // Is last point too far? int marginEnd = waveLength - width; points[npoints-1].x -= marginEnd; switch(getSlope(winx, npoints-1, ww)) { case UNDERCURL_SLOPE_TOP_CAP: points[npoints-1].y += marginEnd; break; case UNDERCURL_SLOPE_BOTTOM_CAP: points[npoints-1].y -= marginEnd; break; default: break; } } // Draw the lines XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, npoints, CoordModeOrigin); // Draw a second underline with an offset of 1 pixel if ( ((win.ch / (widthThreshold/2)) % 2)) { for (int i = 0; i < npoints; i++) points[i].x++; XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, npoints, CoordModeOrigin); } // Free resources free(points); } #endif } XFreeGC(xw.dpy, ugc); } if (base.mode & ATTR_STRUCK) {