static void m2_create_surfaces(MF2UI* ui) { cairo_t* cr; ui->sf_gain = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ANN_W, 40); #define AMPLABEL(V, O, T, X) \ { \ const float ang = (-.75 * M_PI) + (1.5 * M_PI) * ((V) + (O)) / (T); \ xlp = X + .5 + sinf (ang) * (10 + 3.0); \ ylp = 16.5 + .5 - cosf (ang) * (10 + 3.0); \ cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); \ CairoSetSouerceRGBA(ui->c_fg); \ cairo_set_line_width(cr, 1.5); \ cairo_move_to(cr, rint(xlp)-.5, rint(ylp)-.5); \ cairo_close_path(cr); \ cairo_stroke(cr); \ xlp = X + .5 + sinf (ang) * (10 + 9.5); \ ylp = 16.5 + .5 - cosf (ang) * (10 + 9.5); \ } ui->sf_dial = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 60, 40); cr = cairo_create (ui->sf_dial); float xlp, ylp; AMPLABEL(-40, 40., 80., 30.5); write_text_full(cr, "-40", ui->font[0], xlp, ylp, 0, 2, ui->c_fg); AMPLABEL(-30, 40., 80., 30.5); AMPLABEL(-20, 40., 80., 30.5); AMPLABEL(-10, 40., 80., 30.5); AMPLABEL( 0, 40., 80., 30.5); AMPLABEL( 10, 40., 80., 30.5); AMPLABEL( 20, 40., 80., 30.5); AMPLABEL( 30, 40., 80., 30.5); AMPLABEL( 40, 40., 80., 30.5); write_text_full(cr, "+40", ui->font[0], xlp, ylp, 0, 2, ui->c_fg); \ cairo_destroy (cr); }
static void m1_create_surfaces(MF2UI* ui) { cairo_t* cr; ui->sf_pc[0] = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, PC_WIDTH, 16); cr = cairo_create (ui->sf_pc[0]); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba(cr, 0, .0, 0, .0); cairo_rectangle (cr, 0, 0, PC_WIDTH, 20); cairo_fill (cr); write_text_full(cr, "+1", ui->font[1], PC_WIDTH / 2, 10, 0, 2, c_ann); cairo_destroy (cr); ui->sf_pc[1] = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, PC_WIDTH, 16); cr = cairo_create (ui->sf_pc[1]); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba(cr, .0, 0, 0, .0); cairo_rectangle (cr, 0, 0, PC_WIDTH, 20); cairo_fill (cr); write_text_full(cr, "-1", ui->font[1], PC_WIDTH / 2, 10, 0, 2, c_ann); cairo_destroy (cr); }
static void freq_knob (cairo_t* cr, FilterFreq const * const f) { float xlp, ylp; char tfq[8]; PangoFontDescription* font = pango_font_description_from_string("Mono 9px"); print_hz(tfq, dial_to_freq(f, 0)); RESPLABLEL(0.00); write_text_full(cr, tfq, font, xlp, ylp, 0, 1, c_dlf); print_hz(tfq, dial_to_freq(f, .25)); RESPLABLEL(0.25); write_text_full(cr, tfq, font, xlp, ylp, 0, 1, c_dlf); print_hz(tfq, dial_to_freq(f, .50)); RESPLABLEL(0.50); write_text_full(cr, tfq, font, xlp, ylp, 0, 2, c_dlf); print_hz(tfq, dial_to_freq(f, .75)); RESPLABLEL(0.75); write_text_full(cr, tfq, font, xlp-2, ylp, 0, 3, c_dlf); print_hz(tfq, dial_to_freq(f, 1.0)); RESPLABLEL(1.00); write_text_full(cr, tfq, font, xlp-2, ylp, 0, 3, c_dlf); pango_font_description_free (font); }
static void gain_knob (cairo_t* cr) { float xlp, ylp; PangoFontDescription* font = pango_font_description_from_string("Mono 9px"); RESPLABLEL(0.00); write_text_full(cr, "-18", font, xlp, ylp, 0, 1, c_dlf); RESPLABLEL(.16); write_text_full(cr, "-12", font, xlp, ylp, 0, 1, c_dlf); RESPLABLEL(.33); write_text_full(cr, "-6", font, xlp, ylp, 0, 1, c_dlf); RESPLABLEL(0.5); write_text_full(cr, "0dB", font, xlp-1, ylp-1, 0, 2, c_dlf); RESPLABLEL(.66); write_text_full(cr, "+6", font, xlp-3, ylp, 0, 3, c_dlf); RESPLABLEL(.83); write_text_full(cr, "+12", font, xlp-3, ylp, 0, 3, c_dlf); RESPLABLEL(1.0); write_text_full(cr, "+18", font, xlp-3, ylp, 0, 3, c_dlf); pango_font_description_free (font); }
static void update_grid(SFSUI* ui) { cairo_t *cr = cairo_create (ui->sf_ann); cairo_rectangle (cr, 0, 0, ui->width, ui->height); CairoSetSouerceRGBA(ui->c_bg); cairo_fill (cr); cairo_set_line_width (cr, 1.0); rounded_rectangle (cr, SS_BORDER, SS_BORDER, SS_SIZE, SS_SIZE, SS_BORDER); cairo_set_source_rgba(cr, 0, 0, 0, 1.0); cairo_fill(cr); rounded_rectangle (cr, SS_BORDER-.5, SS_BORDER-.5, SS_SIZE+1, SS_SIZE+1, SS_BORDER); CairoSetSouerceRGBA(c_g90); cairo_stroke(cr); const double dash1[] = {1.0, 2.0}; cairo_set_dash(cr, dash1, 2, 0); CairoSetSouerceRGBA(c_grd); #define FREQ_ANN(FRQ, TXT) { \ const float py = rintf(SS_BORDER + SS_SIZE * (1.0 - fast_log10(1.0 + 2 * FRQ * ui->log_rate / ui->rate) / ui->log_base)) + .5; \ cairo_move_to(cr, SS_BORDER, py); \ cairo_line_to(cr, SS_BORDER + SS_SIZE, py); \ cairo_stroke(cr); \ write_text_full(cr, TXT, ui->font[0], SS_SIZE, py, 0, -1, c_ahz); \ } float freq = 62.5; while (freq < ui->rate / 2) { char txt[16]; if (freq < 1000) { snprintf(txt, 16, "%d Hz", (int)ceil(freq)); } else { snprintf(txt, 16, "%d KHz", (int)ceil(freq/1000.f)); } FREQ_ANN(freq, txt); freq *= 2.0; } #define LEVEL_ANN(LVL, TXT) { \ const float dx = .5 * SS_SIZE * (1 - powf(10, .05 * (LVL))); \ const float p0 = .5 + rintf(SS_BORDER + .5 * SS_SIZE + dx); \ const float p1 = .5 + rintf(SS_BORDER + .5 * SS_SIZE - dx); \ cairo_move_to(cr, p0, SS_BORDER); \ cairo_line_to(cr, p0, SS_BORDER + SS_SIZE); \ cairo_stroke(cr); \ cairo_move_to(cr, p1, SS_BORDER); \ cairo_line_to(cr, p1, SS_BORDER + SS_SIZE); \ cairo_stroke(cr); \ write_text_full(cr, TXT, ui->font[0], p0, SS_BORDER + 3, -.5 * M_PI, -1, c_ahz); \ write_text_full(cr, TXT, ui->font[0], p1, SS_BORDER + 3, -.5 * M_PI, -1, c_ahz); \ } LEVEL_ANN(-1, "1dB"); LEVEL_ANN(-3, "3dB"); LEVEL_ANN(-6, "6dB"); LEVEL_ANN(-10, "10dB"); LEVEL_ANN(-20, "20dB"); const double dash2[] = {1.0, 3.0}; cairo_set_line_width(cr, 3.5); cairo_set_dash(cr, dash2, 2, 2); const float xmid = rintf(SS_BORDER + SS_SIZE *.5) + .5; cairo_move_to(cr, xmid, SS_BORDER); cairo_line_to(cr, xmid, SS_BORDER + SS_SIZE); cairo_stroke(cr); write_text_full(cr, "L", ui->font[1], SS_BORDER + 6, SS_BORDER + 12, 0, -2, c_ann); write_text_full(cr, "R", ui->font[1], SS_BORDER + SS_SIZE - 6, SS_BORDER + 12, 0, -2, c_ann); cairo_destroy (cr); }
static bool expose_event (RobWidget* rw, cairo_t* cr, cairo_rectangle_t *ev) { BITui* ui = (BITui*)GET_HANDLE(rw); cairo_rectangle (cr, ev->x, ev->y, ev->width, ev->height); cairo_clip (cr); const int ww = rw->area.width; const int hh = rw->area.height; CairoSetSouerceRGBA(c_g30); cairo_rectangle (cr, 0, 0, ww, hh); cairo_fill (cr); if (!ui->m0_faceplate) { gen_faceplate (ui, ww, hh); } const int spc = (int) floorf ((ww - 28) / 28.) & ~1; const int rad = ceilf (spc * .75); const int x0r = rint (ww * .5 + 12 * spc); const int xpr = rint (ww * .5 - 13 * spc); const int spc_s = (int) floorf (ww / 45.) & ~1; const int rad_s = ceilf (spc_s * .75); const int x0r_s = ww * .5 + 20 * spc_s; const int y0 = hh - 60 - rad_s - spc; const int y0_s = hh - 20 - rad_s; const int y0_g = 10; const int y1_g = y0 - 4; const int yh_g = y1_g - y0_g; // draw distribution if ((int)ui->integration_spl == ui->f_zero) { // all blank draw_bit_dist (cr, xpr, y0_g, rad, yh_g, -1); for (int k = 0; k < 23; ++k) { const float xp = x0r - rintf (spc * (.5 * (k / 8) + k)); draw_bit_dist (cr, xp, y0_g, rad, yh_g, -1); } } else { const float scnt = ui->integration_spl; draw_bit_dist (cr, xpr, y0_g, rad, yh_g, ui->f_pos / scnt); for (int k = 0; k < 23; ++k) { const float xp = x0r - rintf (spc * (.5 * (k / 8) + k)); const float v = ui->flt[k + BIM_DSET] / scnt; draw_bit_dist (cr, xp, y0_g, rad, yh_g, v); } } cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_set_source_surface(cr, ui->m0_faceplate, 0, 0); cairo_paint (cr); /* quick glance boxes */ // sign - bit draw_bit_box (ui, cr, xpr, y0, rad, -1, ui->f_pos); // "+" sign const float mid = .5 + rintf (spc * .75 * .5); const float span = ceilf (spc * .75 * .2); CairoSetSouerceRGBA(c_wht); cairo_set_line_width (cr, 1); cairo_move_to (cr, xpr + mid, y0 + mid - span); cairo_line_to (cr, xpr + mid, y0 + mid + span); cairo_stroke (cr); cairo_move_to (cr, xpr + mid - span, y0 + mid); cairo_line_to (cr, xpr + mid + span, y0 + mid); cairo_stroke (cr); // mantissa for (int k = 0; k < 23; ++k) { const float xp = x0r - rintf (spc * (.5 * (k / 8) + k)); draw_bit_box (ui, cr, xp, y0, rad, -1, ui->flt[k + BIM_DSET]); } // magnitude for (int k = 0; k < 40; ++k) { const int o = k + 118; const float xp = .5 * (k / 8) + k; draw_bit_box (ui, cr, x0r_s - rintf (xp * spc_s), y0_s, rad_s, ui->flt[o + BIM_DHIT], ui->flt[o + BIM_DONE]); } if (ui->integration_spl == 0) { cairo_set_source_rgba (cr, 0, 0, 0, .6); cairo_rectangle (cr, 0, 0, ww, hh); cairo_fill (cr); write_text_full (cr, "<markup><b>No data available.</b></markup>", FONT(FONT_S), rintf(ww * .5f), rintf(hh * .5f), 0, 2, c_wht); } else if (ui->integration_spl >= 2147483647) { cairo_set_source_rgba (cr, .9, .9, .9, .5); cairo_rectangle (cr, 0, 0, ww, hh); cairo_fill (cr); write_text_full (cr, "<markup>Reached <b>2<sup><small>31</small></sup> sample limit.\nData acquisition suspended.</b></markup>", FONT(FONT_S), rintf(ww * .5f), rintf(hh * .5f), 0, 2, c_blk); } else if ((int)ui->integration_spl == ui->f_zero) { // all blank write_text_full (cr, "<markup><b>All samples are zero.</b></markup>", FONT(FONT_S), rintf(ww * .5f), rintf(y0_g + yh_g * .5f), 0, 2, c_wht); } return TRUE; }
static void gen_faceplate (BITui* ui, const int ww, const int hh) { assert(!ui->m0_faceplate); ui->m0_faceplate = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ww, hh); cairo_t* cr = cairo_create (ui->m0_faceplate); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); const int spc = (int) floorf ((ww - 28) / 28.) & ~1; const int rad = ceilf (spc * .75); const int mid = rint (spc * .75 * .5); const int x0r = rint (ww * .5 + 12 * spc); const int xpr = rint (ww * .5 - 13 * spc); const int spc_s = (int) floorf (ww / 45.) & ~1; const int rad_s = ceilf (spc_s * .75); const int x0r_s = ww * .5 + 20 * spc_s; const int y0 = hh - 60 - rad_s - spc; const int y0_s = hh - 20 - rad_s; const int y0_g = 10; const int y1_g = y0 - 4; const int yh_g = y1_g - y0_g; // grid & annotations -- TODO statically allocate surface const float x0_g = xpr - 2; const float x1_b = x0r + rad + 2; const float x1_g = x1_b + mid + 2; const float yc_g = rintf (y0_g + .5 * yh_g); const float y6_g = rintf (y0_g + yh_g * 2. / 3.); const float y3_g = rintf (y0_g + yh_g / 3.); cairo_rectangle (cr, x1_b, y0_g, mid, y3_g); cairo_set_source_rgba (cr, .8, .5, .1, 1.0); cairo_fill (cr); cairo_rectangle (cr, x1_b, y3_g, mid, y6_g - y3_g); cairo_set_source_rgba (cr, .1, .9, .1, 1.0); cairo_fill (cr); cairo_rectangle (cr, x1_b, y6_g, mid, y1_g - y6_g); cairo_set_source_rgba (cr, .1, .6, .9, 1.0); cairo_fill (cr); cairo_set_line_width (cr, 2); cairo_move_to (cr, x1_b, y0_g); cairo_line_to (cr, x1_b + mid, y0_g); cairo_set_source_rgba (cr, .9, .0, .0, 1.0); cairo_stroke (cr); cairo_move_to (cr, x1_b, y0_g + yh_g); cairo_line_to (cr, x1_b + mid, y0_g + yh_g); cairo_set_source_rgba (cr, .0, .0, .9, 1.0); cairo_stroke (cr); CairoSetSouerceRGBA(c_g80); cairo_set_line_width (cr, 1); cairo_save (cr); double dash = 1; cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); cairo_set_dash (cr, &dash, 1, 0); cairo_move_to (cr, x0_g, y0_g - .5); cairo_line_to (cr, x1_b, y0_g - .5); cairo_stroke (cr); cairo_move_to (cr, x0_g, .5 + yc_g); cairo_line_to (cr, x0_g + spc + 4, .5 + yc_g); cairo_stroke (cr); cairo_move_to (cr, x0_g, .5 + y6_g); cairo_line_to (cr, x1_b, .5 + y6_g); cairo_stroke (cr); cairo_move_to (cr, x0_g, .5 + y3_g); cairo_line_to (cr, x1_b, .5 + y3_g); cairo_stroke (cr); cairo_move_to (cr, x0_g, y1_g + .5); cairo_line_to (cr, x1_b, y1_g + .5); cairo_stroke (cr); cairo_restore (cr); cairo_move_to (cr, 1.5 + rintf (x0r_s - 33 * spc_s), y0_s - 1.5); cairo_line_to (cr, 1.5 + rintf (x0r_s - 33 * spc_s), y0_s + rad_s + 3.5); cairo_line_to (cr, .5 + rintf (x0r_s - 35.5 * spc_s), y0_s + rad_s + 3.5); cairo_stroke (cr); write_text_full (cr, ">1.0", FONT(FONT_M), x0r_s - 33.0 * spc_s, hh - 2, 0, 4, c_wht); write_text_full (cr, "<markup>2<small><sup>-32</sup></small></markup>", FONT(FONT_M), x0r_s + 0.5 * spc_s, hh - 2, 0, 5, c_wht); write_text_full (cr, "<markup>2<small><sup>-24</sup></small></markup>", FONT(FONT_M), x0r_s - 8.0 * spc_s, hh - 2, 0, 5, c_wht); write_text_full (cr, "<markup>2<small><sup>-16</sup></small></markup>", FONT(FONT_M), x0r_s - 16.5 * spc_s, hh - 2, 0, 5, c_wht); write_text_full (cr, "<markup>2<small><sup>-8</sup></small></markup>", FONT(FONT_M), x0r_s - 25.0 * spc_s, hh - 2, 0, 5, c_wht); write_text_full (cr, "<markup>2<small><sup>7</sup></small></markup>", FONT(FONT_M), x0r_s - 40.5 * spc_s, hh - 2, 0, 5, c_wht); write_text_full (cr, "% time bit is set", FONT(FONT_M), x1_g, yc_g, -.5 * M_PI, 8, c_wht); write_text_full (cr, "100%", FONT(FONT_M), x0_g - 2, y0_g, 0, 1, c_wht); write_text_full (cr, "50%", FONT(FONT_M), x0_g - 2, yc_g, 0, 1, c_wht); write_text_full (cr, "0%", FONT(FONT_M), x0_g - 2, y1_g, 0, 1, c_wht); // sep int ysep = .5 * (y0 + rad + y0_s); CairoSetSouerceRGBA(c_g60); cairo_move_to (cr, 15, ysep + .5); cairo_line_to (cr, ww - 30 , ysep + .5); cairo_stroke (cr); write_text_full (cr, "Sign & Mantissa (23bit significand)", FONT(FONT_S), ww * .5, ysep - 2, 0, 5, c_wht); write_text_full (cr, "Full Scale", FONT(FONT_S), ww * .5, ysep + 3, 0, 8, c_wht); write_text_full (cr, ui->nfo, FONT(FONT_M), 2, hh -2, 1.5 * M_PI, 9, c_gry); cairo_destroy (cr); }
/** draw level-range display * depends on gain (dial) and cutoff */ static void update_annotations(MF2UI* ui) { cairo_t* cr = cairo_create (ui->sf_gain); cairo_rectangle (cr, 0, 0, ANN_W, 40); CairoSetSouerceRGBA(ui->c_bg); cairo_fill (cr); rounded_rectangle (cr, 3, 3 , ANN_W - 6, ANN_H - 6, 6); if (ui->drag_cutoff_x >= 0 || ui->prelight_cutoff) { cairo_set_source_rgba(cr, .15, .15, .15, 1.0); } else { cairo_set_source_rgba(cr, .0, .0, .0, 1.0); } cairo_fill (cr); cairo_set_line_width (cr, 1.0); const uint32_t mxw = ANN_W - XOFF * 2 - 36; const uint32_t mxo = XOFF + 18; const float cutoff = ui->db_cutoff; const uint32_t cutoff_m = floor(mxw * (MIN_CUTOFF - cutoff) / MIN_CUTOFF); assert(cutoff_m < mxw); const uint32_t cutoff_w = mxw - cutoff_m; for (uint32_t i=0; i < mxw; ++i) { float clr[3]; if (i < cutoff_m) { clr[0] = clr[1] = clr[2] = .1; } else { const float pk = (i-cutoff_m) / (float)cutoff_w; hsl2rgb(clr, .68 - .72 * pk, .9, .2 + pk * .4); } cairo_set_source_rgba(cr, clr[0], clr[1], clr[2], 1.0); cairo_move_to(cr, mxo + i + .5, ANN_B - 5); cairo_line_to(cr, mxo + i + .5, ANN_B); cairo_stroke(cr); } cairo_set_source_rgba(cr, .8, .8, .8, .8); const float gain = robtk_dial_get_value(ui->gain); for (int32_t db = MIN_CUTOFF; db <=0 ; db+= 10) { char dbt[16]; if (db == 0) { snprintf(dbt, 16, "\u2265%+.0fdB", (db - gain)); } else { snprintf(dbt, 16, "%+.0fdB", (db - gain)); } write_text_full(cr, dbt, ui->font[0], mxo + rint(mxw * (-MIN_CUTOFF + db) / -MIN_CUTOFF), ANN_B - 14 , 0, 2, c_wht); cairo_move_to(cr, mxo + rint(mxw * (-MIN_CUTOFF + db) / -MIN_CUTOFF) + .5, ANN_B - 7); cairo_line_to(cr, mxo + rint(mxw * (-MIN_CUTOFF + db) / -MIN_CUTOFF) + .5, ANN_B); cairo_stroke(cr); } /* black overlay above low-end cutoff */ if (ui->db_cutoff > MIN_CUTOFF && (ui->drag_cutoff_x >= 0 || ui->prelight_cutoff)) { const float cox = rint(mxw * (ui->db_cutoff - MIN_CUTOFF)/ -MIN_CUTOFF); cairo_rectangle(cr, mxo, 6, cox, ANN_B - 6); cairo_set_source_rgba(cr, .0, .0, .0, .7); cairo_fill(cr); cairo_set_line_width (cr, 1.0); cairo_set_source_rgba(cr, .9, .5, .5, .6); cairo_move_to(cr, mxo + cox + .5, ANN_B - 6); cairo_line_to(cr, mxo + cox + .5, ANN_B + 1); cairo_stroke(cr); } cairo_destroy (cr); }
/** draw frequency calibration circles * and on screen annotations - sample-rate dependent */ static void update_grid(MF2UI* ui) { const double ccc = ui->width / 2.0 + .5; const double rad = (ui->width - XOFF) * .5; cairo_t *cr = cairo_create (ui->sf_ann); cairo_rectangle (cr, 0, 0, ui->width, ui->height); CairoSetSouerceRGBA(ui->c_bg); cairo_fill (cr); cairo_set_line_width (cr, 1.0); cairo_arc (cr, ccc, ccc, rad, 0, 2.0 * M_PI); cairo_set_source_rgba(cr, 0, 0, 0, 1.0); cairo_fill_preserve(cr); CairoSetSouerceRGBA(c_g90); cairo_stroke(cr); const double dash1[] = {1.0, 2.0}; cairo_set_dash(cr, dash1, 2, 0); CairoSetSouerceRGBA(c_grd); float freq = 62.5; while (freq < ui->rate / 2) { char txt[16]; if (freq < 1000) { snprintf(txt, 16, "%d Hz", (int)ceil(freq)); } else { snprintf(txt, 16, "%d KHz", (int)ceil(freq/1000.f)); } { const float dr = ui->scale * PH_RAD * fast_log10(1.0 + 2 * freq * ui->log_rate / ui->rate) / ui->log_base; cairo_arc (cr, ccc, ccc, dr, 0, 2.0 * M_PI); cairo_stroke(cr); const float px = ccc + dr * sinf(M_PI * -.75); const float py = ccc - dr * cosf(M_PI * -.75); write_text_full(cr, txt, ui->font[0], px, py, M_PI * -.75, -2, c_ahz); } freq *= 2.0; } const double dash2[] = {1.0, 3.0}; cairo_set_line_width(cr, 3.5); cairo_set_dash(cr, dash2, 2, 2); cairo_set_line_width(cr, 1.5); cairo_move_to(cr, ccc - rad, ccc); cairo_line_to(cr, ccc + rad, ccc); cairo_stroke(cr); cairo_set_line_width(cr, 3.5); cairo_move_to(cr, ccc, ccc - rad); cairo_line_to(cr, ccc, ccc + rad); cairo_stroke(cr); cairo_set_dash(cr, NULL, 0, 0); write_text_full(cr, "+L", ui->font[0], ccc, ccc - rad * .92, 0, -2, c_ann); write_text_full(cr, "-L", ui->font[0], ccc, ccc + rad * .92, 0, -2, c_ann); write_text_full(cr, "0\u00B0", ui->font[0], ccc, ccc - rad * .80, 0, -2, c_ann); write_text_full(cr, "180\u00B0", ui->font[0], ccc, ccc + rad * .80, 0, -2, c_ann); write_text_full(cr, "-R", ui->font[0], ccc - rad * .92, ccc, 0, -2, c_ann); write_text_full(cr, "+R", ui->font[0], ccc + rad * .92, ccc, 0, -2, c_ann); write_text_full(cr, "-90\u00B0", ui->font[0], ccc - rad * .80, ccc, 0, -2, c_ann); write_text_full(cr, "+90\u00B0", ui->font[0], ccc + rad * .80, ccc, 0, -2, c_ann); cairo_destroy (cr); }