/*************************************************************************** * draw.c - ruler window rendering * * Fri Sep 24 02:56:24 2004 * Copyright 2004 imcintosh * ian_mcintosh@linuxadvocate.org ****************************************************************************/ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "../include/main.h" #include "../include/gui.h" #define TEXT_BOX_RELIEF (1) // gap between text and box outline for mouse position tracking static void draw_centered_label(const gchar* pText, GdkDrawable* pDrawable, GdkGC* pGC, PangoLayout* pPangoLayout, GdkColor* pClrForeground, GdkColor* pClrBackground, gint nX, gint nY); gboolean draw_ruler_window(GtkWidget* pDrawingArea) { // g_message("draw_ruler_window"); g_return_val_if_fail(pDrawingArea != NULL, FALSE); if(pDrawingArea->window == NULL) return FALSE; // don't generate a warning // Extract pixmap pointer from window data GdkPixmap* pPixmap = g_object_get_data(G_OBJECT(pDrawingArea), KEY_PIXMAP_POINTER); g_return_val_if_fail(pPixmap != NULL, FALSE); // Get top-level window and figure out orientation from window data GtkWidget* pTopLevel = gtk_widget_get_toplevel(pDrawingArea); RulerOrientation eRulerOrientation = gui_get_ruler_orientation(GTK_WINDOW(pTopLevel)); // (for easy access) gint nWindowWidth = pDrawingArea->allocation.width; gint nWindowHeight = pDrawingArea->allocation.height; // Save GC values GdkGCValues gcsave; gdk_gc_get_values(pDrawingArea->style->fg_gc[GTK_WIDGET_STATE(pDrawingArea)], &gcsave); // Create a Pango layout for text rendering PangoLayout* pPangoLayout = gtk_widget_create_pango_layout(pDrawingArea, NULL); g_return_val_if_fail(pPangoLayout != NULL, FALSE); // Set the font from the Pref dialog PangoFontDescription *pPangoFontDescription = pango_font_description_from_string(gui_get_font_string()); pango_layout_set_font_description(pPangoLayout, pPangoFontDescription); //======================================= // Begin drawing //======================================= // Find background color, and fill window with it GdkColor clrBackground; gui_get_background_color(&clrBackground); gdk_gc_set_rgb_fg_color(pDrawingArea->style->fg_gc[GTK_WIDGET_STATE(pDrawingArea)], &clrBackground); gdk_draw_rectangle(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], TRUE, // filled (not outlined) 0, 0, nWindowWidth, nWindowHeight); // Outline the whole window with foreground color GdkColor clrForeground; gui_get_foreground_color(&clrForeground); gdk_gc_set_rgb_fg_color(pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], &clrForeground); gdk_draw_rectangle(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], FALSE, // outlined 0, 0, nWindowWidth-1, nWindowHeight-1); // must use -1 (read help on unfilled rects) ERulerMetric eRulerMetric = gui_get_ruler_metric(); int nOverdraw = 100; // overdraw by 100 so the next text label is guaranteed to be drawn gint nRulerLength = (eRulerOrientation == RulerOrientationHorizontal) ? nWindowWidth : nWindowHeight; gint nDotsPerInch = gui_get_dots_per_inch(); switch(eRulerMetric) { case RulerMetricPixels: { int nX=0; int nLineLength=0; for(nX = 0 ; nX < nRulerLength + nOverdraw ; nX++) { if(nX % 50 == 0) nLineLength = 15; else if(nX % 10 == 0) nLineLength = 10; else if(nX % 2 == 0) nLineLength = 6; else continue; // no tick here if(eRulerOrientation == RulerOrientationHorizontal) { gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nX, 0, nX, 0 + nLineLength); // top line gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nX, nWindowHeight, nX, nWindowHeight - nLineLength); // bottom line } else { gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], 0, nX, 0 + nLineLength, nX); // top line gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nWindowWidth, nX, nWindowWidth - nLineLength, nX); // bottom line } // Text labels every 100 pixels (let gtk clip it if necessary) if(nX % 100 == 0 && nX != 0) { gchar buffer[100]; g_snprintf(buffer, 100, (nX == 100) ? "%dpx" : "%d", nX); if(eRulerOrientation == RulerOrientationHorizontal) { draw_centered_label(buffer, pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE(pDrawingArea)], pPangoLayout, &clrForeground, NULL, nX, nWindowHeight/2); } else { draw_centered_label(buffer, pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE(pDrawingArea)], pPangoLayout, &clrForeground, NULL, nWindowWidth/2, nX); } } } } break; case RulerMetricCentimeters: { // draw in centimeters gint anLineLengths[10] = {15, 9, 9, 9, 9, 15, 9, 9, 9, 9}; // draw in inches int nLineLength=0; gfloat fDotsPerCentimeter = (gfloat)nDotsPerInch / (gfloat)CM_PER_INCH; gint nTotalCentimeters = (gint)((gfloat)nRulerLength / fDotsPerCentimeter) + 1; gint nCentimeter; // for each Centimeter... for(nCentimeter = 0 ; nCentimeter < (nTotalCentimeters + 1) ; nCentimeter++) { // Draw the 10 tick marks for this Centimeter gfloat fX = ((gfloat)nCentimeter * fDotsPerCentimeter); // use float to avoid accumulating roundoff error gint i; for(i = 0 ; i < 10 ; i++) { // how long should this line be? nLineLength = anLineLengths[i]; // drawing must be in integer gint nX = (gint)fX; // draw a tick mark if(eRulerOrientation == RulerOrientationHorizontal) { gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nX, 0, nX, 0 + nLineLength); // top line gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nX, nWindowHeight, nX, nWindowHeight - nLineLength); // bottom line } else { gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], 0, nX, 0 + nLineLength, nX); // left line gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nWindowWidth, nX, nWindowWidth - nLineLength, nX); // right line } // move forward to next tick (one millimeter aka one tenth of a Centimeter) fX += (fDotsPerCentimeter / 10.0); } // draw an inch label # (not @ zero inches) if(nCentimeter >= 1) { gchar buffer[100]; g_snprintf(buffer, 100, (nCentimeter==1) ? "%dcm" : "%d", nCentimeter); if(eRulerOrientation == RulerOrientationHorizontal) { draw_centered_label(buffer, pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE(pDrawingArea)], pPangoLayout, &clrForeground, NULL, (gint)(nCentimeter * fDotsPerCentimeter), nWindowHeight/2); } else { draw_centered_label(buffer, pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE(pDrawingArea)], pPangoLayout, &clrForeground, NULL, nWindowWidth/2, (gint)(nCentimeter * fDotsPerCentimeter)); } } } } break; case RulerMetricInches: { gint anLineLengths[8] = {15, 9, 12, 9, 15, 9 , 12, 9}; // draw in inches int nLineLength=0; gint nTotalInches = (gint)(nRulerLength / nDotsPerInch) + 1; gint nInch; // for each inch... for(nInch = 0 ; nInch < (nTotalInches + 1) ; nInch++) { // Draw the 8 tick marks for this inch gfloat fX = (gfloat)(nInch * nDotsPerInch); // use float to avoid accumulating roundoff error gint i; for(i = 0 ; i < 8 ; i++) { // how long should this line be? nLineLength = anLineLengths[i]; // drawing must be in integer gint nX = (gint)fX; // draw a tick mark if(eRulerOrientation == RulerOrientationHorizontal) { gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nX, 0, nX, 0 + nLineLength); // top line gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nX, nWindowHeight, nX, nWindowHeight - nLineLength); // bottom line } else { gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], 0, nX, 0 + nLineLength, nX); // left line gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nWindowWidth, nX, nWindowWidth - nLineLength, nX); // right line } // move forward to next tick (one eighth of an inch) fX += ((gfloat)nDotsPerInch / 8.0); } // draw an inch label # (not @ zero inches) if(nInch >= 1) { gchar buffer[100]; g_snprintf(buffer, 100, (nInch==1) ? "%din" : "%d", nInch); if(eRulerOrientation == RulerOrientationHorizontal) { draw_centered_label(buffer, pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE(pDrawingArea)], pPangoLayout, &clrForeground, NULL, (nInch * nDotsPerInch), nWindowHeight/2); } else { draw_centered_label(buffer, pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE(pDrawingArea)], pPangoLayout, &clrForeground, NULL, nWindowWidth/2, (nInch * nDotsPerInch)); } } } } break; case RulerMetricPicas: { gint anLineLengths[6] = {15, 12, 12, 15, 12, 12}; // draw in picas, which are 6 to an inch. // this is basically the same code as for inches, except we // break up the inch into 6 units instead of 8. int nLineLength=0; gint nTotalInches = (gint)(nRulerLength / nDotsPerInch) + 1; gint nInch; // for each inch... for(nInch = 0 ; nInch < (nTotalInches + 1) ; nInch++) { // Draw the 8 tick marks for this inch gfloat fX = (gfloat)(nInch * nDotsPerInch); // use float to avoid accumulating roundoff error gint i; for(i = 0 ; i < 6 ; i++) { // how long should this line be? nLineLength = anLineLengths[i]; // drawing must be in integer gint nX = (gint)fX; // draw a tick mark if(eRulerOrientation == RulerOrientationHorizontal) { gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nX, 0, nX, 0 + nLineLength); // top line gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nX, nWindowHeight, nX, nWindowHeight - nLineLength); // bottom line } else { gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], 0, nX, 0 + nLineLength, nX); // left line gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nWindowWidth, nX, nWindowWidth - nLineLength, nX); // right line } // move forward to next tick (one eighth of an inch) fX += ((gfloat)nDotsPerInch / 6.0); } // draw an inch label # (not @ zero inches) if(nInch >= 1) { gchar buffer[100]; g_snprintf(buffer, 100, (nInch==1) ? "%dpc" : "%d", 6*nInch); if(eRulerOrientation == RulerOrientationHorizontal) { draw_centered_label(buffer, pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE(pDrawingArea)], pPangoLayout, &clrForeground, NULL, (nInch * nDotsPerInch), nWindowHeight/2); } else { draw_centered_label(buffer, pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE(pDrawingArea)], pPangoLayout, &clrForeground, NULL, nWindowWidth/2, (nInch * nDotsPerInch)); } } } } break; case RulerMetricPoints: { gint anLineLengths[12] = {15, 9, 9, 9, 9, 9, 12, 9, 9, 9, 9, 9}; // draw in picas, which are 6 to an inch. // this is basically the same code as for inches, except we // break up the inch into 6 units instead of 8. int nLineLength=0; gint nTotalInches = (gint)(nRulerLength / nDotsPerInch) + 1; gint nInch; // for each inch... for(nInch = 0 ; nInch < (nTotalInches + 1) ; nInch++) { // Draw the 8 tick marks for this inch gfloat fX = (gfloat)(nInch * nDotsPerInch); // use float to avoid accumulating roundoff error gint i; for(i = 0 ; i < 12 ; i++) { // how long should this line be? nLineLength = anLineLengths[i]; // drawing must be in integer gint nX = (gint)fX; // draw a tick mark if(eRulerOrientation == RulerOrientationHorizontal) { gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nX, 0, nX, 0 + nLineLength); // top line gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nX, nWindowHeight, nX, nWindowHeight - nLineLength); // bottom line } else { gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], 0, nX, 0 + nLineLength, nX); // left line gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nWindowWidth, nX, nWindowWidth - nLineLength, nX); // right line } // move forward to next tick (one eighth of an inch) fX += ((gfloat)nDotsPerInch / 12.0); } // draw an inch label # (not @ zero inches) if(nInch >= 1) { gchar buffer[100]; g_snprintf(buffer, 100, (nInch==1) ? "%dpt" : "%d", 12*6*nInch); if(eRulerOrientation == RulerOrientationHorizontal) { draw_centered_label(buffer, pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE(pDrawingArea)], pPangoLayout, &clrForeground, NULL, (nInch * nDotsPerInch), nWindowHeight/2); } else { draw_centered_label(buffer, pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE(pDrawingArea)], pPangoLayout, &clrForeground, NULL, nWindowWidth/2, (nInch * nDotsPerInch)); } } } } break; case RulerMetricPercentage: { gint nNumParts; // how many parts should we break the ruler up into? (1 to 20) // a minimum of 40 pixels per part if(nRulerLength > 800) nNumParts = 20; else if(nRulerLength > 400) nNumParts = 10; else if(nRulerLength > 160) nNumParts = 4; else if(nRulerLength > 80) nNumParts = 2; else nNumParts = 1; // really show twice as many, because each will have a small tick inside it nNumParts *= 2; gfloat fPartSize = (gfloat)nRulerLength / (gfloat)nNumParts; gint nPart; for(nPart = 1 ; nPart < nNumParts ; nPart++) { gint nLineLength; if(nPart % 2 == 0) nLineLength = 15; else nLineLength = 9; gint nX = (gint)((gfloat)nPart * fPartSize); // draw a tick mark if(eRulerOrientation == RulerOrientationHorizontal) { gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nX, 0, nX, 0 + nLineLength); // top line gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nX, nWindowHeight, nX, nWindowHeight - nLineLength); // bottom line } else { gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], 0, nX, 0 + nLineLength, nX); // left line gdk_draw_line(pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], nWindowWidth, nX, nWindowWidth - nLineLength, nX); // right line } // only show a # every other two if(nPart % 2 == 0) { gchar buffer[100]; g_snprintf(buffer, 100, (nPart==2) ? "%d%%" : "%d", (nPart * 100) / nNumParts); if(eRulerOrientation == RulerOrientationHorizontal) { draw_centered_label(buffer, pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE(pDrawingArea)], pPangoLayout, &clrForeground, NULL, nX, nWindowHeight/2); } else { draw_centered_label(buffer, pPixmap, pDrawingArea->style->fg_gc[GTK_WIDGET_STATE(pDrawingArea)], pPangoLayout, &clrForeground, NULL, nWindowWidth/2, nX); } } } } break; default: // do nothing? break; } // Restore gc values gdk_gc_set_values(pDrawingArea->style->fg_gc[GTK_WIDGET_STATE (pDrawingArea)], &gcsave, GDK_GC_FOREGROUND | GDK_GC_BACKGROUND); return TRUE; } void draw_ruler_window_overlay(GtkWidget* pDrawingArea, RulerOrientation eRulerOrientation) { gint nWindowWidth = pDrawingArea->allocation.width; gint nWindowHeight = pDrawingArea->allocation.height; gint nMouseX, nMouseY; gdk_window_get_pointer(pDrawingArea->window, &nMouseX, &nMouseY, NULL); // Set text style and measure text PangoLayout* pPangoLayout = gtk_widget_create_pango_layout(pDrawingArea, NULL); g_return_if_fail(pPangoLayout != NULL); PangoFontDescription *pPangoFontDescription = pango_font_description_from_string(gui_get_font_string()); pango_layout_set_font_description(pPangoLayout, pPangoFontDescription); // TODO: free any of these? gint32 nClippedMouseX = max(nMouseX, 0); nClippedMouseX = min(nClippedMouseX, nWindowWidth); gint32 nClippedMouseY = max(nMouseY, 0); nClippedMouseY = min(nClippedMouseY, nWindowHeight); ERulerMetric eRulerMetric = gui_get_ruler_metric(); gchar buffer[100]; gint nPixelOffset = (eRulerOrientation == RulerOrientationHorizontal) ? nClippedMouseX : nClippedMouseY; gint nRulerLength = (eRulerOrientation == RulerOrientationHorizontal) ? nWindowWidth : nWindowHeight; gint nDotsPerInch = gui_get_dots_per_inch(); // swap direction //nPixelOffset = nRulerLength - nPixelOffset; switch(eRulerMetric) { case RulerMetricPixels: { g_snprintf(buffer, 100, "%d", nPixelOffset); } break; case RulerMetricCentimeters: { gfloat fDotsPerCentimeter = (gfloat)nDotsPerInch / (gfloat)CM_PER_INCH; g_snprintf(buffer, 100, "%5.2f", (gfloat)nPixelOffset / fDotsPerCentimeter); } break; case RulerMetricInches: { g_snprintf(buffer, 100, "%5.2f", (gfloat)nPixelOffset / (gfloat)nDotsPerInch); } break; case RulerMetricPicas: { g_snprintf(buffer, 100, "%5.2f", PICAS_PER_INCH * ((gfloat)nPixelOffset / (gfloat)nDotsPerInch)); } break; case RulerMetricPoints: { g_snprintf(buffer, 100, "%5.2f", POINTS_PER_PICA * PICAS_PER_INCH * ((gfloat)nPixelOffset / (gfloat)nDotsPerInch)); } break; case RulerMetricPercentage: { g_snprintf(buffer, 100, "%4.1f", 100.0 * ((gfloat)nPixelOffset / (gfloat)nRulerLength)); } break; default: g_snprintf(buffer, 100, "%d?", eRulerMetric); break; } pango_layout_set_text(pPangoLayout, buffer, -1); // Measure the text int nTextWidth = 0, nTextHeight = 0; pango_layout_get_pixel_size(pPangoLayout, &nTextWidth, &nTextHeight); int nBoxWidth = nTextWidth + (TEXT_BOX_RELIEF*2); int nBoxHeight = nTextHeight + (TEXT_BOX_RELIEF*2); //======================= // Begin drawing //======================= GdkGCValues gcSavedValues; GdkGC* pGC = pDrawingArea->style->fg_gc[GTK_WIDGET_STATE(pDrawingArea)]; // == Draw background line GdkColor clrLine = {0, 65535, 65535, 65535}; gdk_gc_get_values(pGC, &gcSavedValues); gdk_gc_set_rgb_fg_color(pGC, &clrLine); gdk_gc_set_function(pGC, GDK_XOR); if(eRulerOrientation == RulerOrientationHorizontal) { gdk_draw_line(pDrawingArea->window, pGC, nClippedMouseX, 0, nClippedMouseX, nWindowHeight); } else { gdk_draw_line(pDrawingArea->window, pGC, 0, nClippedMouseY, nWindowWidth, nClippedMouseY); } gdk_gc_set_values(pGC, &gcSavedValues, GDK_GC_FUNCTION | GDK_GC_FOREGROUND); // // Draw mouse tracking box around text // GdkColor clrTextBoxBackground = {0, 62000, 62000, 62000}; GdkColor clrTextBoxOutline = {0, 0, 0, 0}; GdkColor clrText = {0, 0, 0, 0}; gdk_gc_get_values(pGC, &gcSavedValues); // determine where to draw mouse tracking box gint nBoxCenterX; gint nBoxCenterY; // centered on the mouse in the length direction, centered on the ruler's width // clip it to the window, though. if(eRulerOrientation == RulerOrientationHorizontal) { nBoxCenterX = max(nMouseX, 0 + (nBoxWidth/2)); nBoxCenterX = min(nBoxCenterX, nWindowWidth - (nBoxWidth/2));; nBoxCenterY = (nWindowHeight / 2); } else { nBoxCenterX = (nWindowWidth/2); nBoxCenterY = max(nMouseY, 0 + (nBoxHeight/2)); nBoxCenterY = min(nBoxCenterY, nWindowHeight - (nBoxHeight/2)); } // draw box background gdk_gc_set_rgb_fg_color(pGC, &clrTextBoxBackground); gdk_draw_rectangle(pDrawingArea->window, pGC, TRUE, nBoxCenterX - (nBoxWidth/2), (nBoxCenterY) - (nBoxHeight/2), nBoxWidth, nBoxHeight); // draw box outline gdk_gc_set_rgb_fg_color(pGC, &clrTextBoxOutline); gdk_draw_rectangle(pDrawingArea->window, pGC, FALSE, nBoxCenterX - (nBoxWidth/2), (nBoxCenterY) - (nBoxHeight/2), nBoxWidth, nBoxHeight); gdk_gc_set_values(pGC, &gcSavedValues, GDK_GC_FOREGROUND); // Draw text, centered and colored gdk_draw_layout_with_colors(pDrawingArea->window, pGC, nBoxCenterX - (nTextWidth / 2), // center text horizontally on point nBoxCenterY - (nTextHeight / 2), // center text vertically on point pPangoLayout, &clrText, NULL); } // draws given text centered on given point static void draw_centered_label(const gchar* pText, GdkDrawable* pDrawable, GdkGC* pGC, PangoLayout* pPangoLayout, GdkColor* pClrForeground, GdkColor* pClrBackground, gint nX, gint nY) { pango_layout_set_text(pPangoLayout, pText, -1); // measure text int nTextWidth = 0, nTextHeight = 0; pango_layout_get_pixel_size(pPangoLayout, &nTextWidth, &nTextHeight); // draw text, centered and colored gdk_draw_layout_with_colors(pDrawable, pGC, nX - (nTextWidth / 2), // center text horizontally on point nY - (nTextHeight / 2), // center text vertically on point pPangoLayout, pClrForeground, pClrBackground); }