std::string Font::wrap_to_width(const std::string& s_, float width, std::string* overflow) { std::string s = s_; // if text is already smaller, return full text if (get_text_width(s) <= width) { if (overflow) *overflow = ""; return s; } // if we can find a whitespace character to break at, return text up to this character for (int i = s.length()-1; i >= 0; i--) { std::string s2 = s.substr(0,i); if (s[i] != ' ') continue; if (get_text_width(s2) <= width) { if (overflow) *overflow = s.substr(i+1); return s.substr(0, i); } } // FIXME: hard-wrap at width, taking care of multibyte characters if (overflow) *overflow = ""; return s; }
void setFontValues(struct Tracker_Windows *window){ double width3 = R_MAX(get_text_width("D#6"), R_MAX(get_text_width("MUL"), get_text_width("STP"))); window->fontwidth = (int)ceil(width3/3.0); window->fontheight = get_text_height("D#6"); //window->fontheight = pango_font_description_get_size(font_description)/PANGO_SCALE; window->org_fontheight = window->fontheight; }
void text_entry::refresh_render_text_part(render_text_part& part, const render_text_part* previous_part, int begin_pos, int end_pos, const rectf& all_parts_area) { int visible_begin_pos = std::max(_visible_pos, begin_pos); int unclipped_char_count = std::max(0, end_pos - visible_begin_pos); part._unclipped_text.assign(_text.c_str(), visible_begin_pos, unclipped_char_count); raw_text_to_visible_text(part._unclipped_text); part._clipped_text.assign(L""); float clipped_text_width = 0.f; pointf clipped_top_left = all_parts_area.get_top_left(); if (previous_part != nullptr) { clipped_top_left = previous_part->_area.get_top_right(); } const float available_width = all_parts_area.get_right() - clipped_top_left._x; size_t clipped_char_count = part._unclipped_text.length(); while (clipped_char_count >= 0) { part._clipped_text.assign(part._unclipped_text.c_str(), 0, clipped_char_count); clipped_text_width = get_text_width(part._clipped_text); if (previous_part != nullptr && !previous_part->_clipped_text.empty()) { clipped_text_width += get_kerning_pair_offset( previous_part->_clipped_text[previous_part->_clipped_text.length() - 1], part._clipped_text[0]); } if (clipped_text_width <= available_width) { break; } } part._area = rectf(clipped_top_left, sizef(clipped_text_width, all_parts_area.get_height())); }
/* Right-clicking on the table can pop up a menu. */ gboolean table_handle_menuclick_event(GdkEventButton * event) { int p; for (p = 0; p < ggzcards.num_players; p++) { int seat_num = ggzcards.players[p].ggzseat; GGZSeat seat; int w = get_text_width(); int x, y; if (seat_num < 0) continue; get_text_box_pos(p, &x, &y); x += XWIDTH; y += XWIDTH; if (event->x < x || event->x >= x + w || event->y < y || event->y >= y + w) continue; seat = ggzmod_get_seat(client_get_ggzmod(), seat_num); popup_player_menu(&seat, NULL, event->button); return TRUE; } return FALSE; }
void View::draw_help() { set_ortho_projection(true); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_1D); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); const char* text = get_help_text(); int n = 1; for (const char* p = text; *p; p++) if (*p == '\n') n++; int width = get_text_width(text); int height = n * glutBitmapHeight(GLUT_BITMAP_9_BY_15); int x = 10, y = 10, b = 6; glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(1.0f, 1.0f, 1.0f, 0.65f); glBegin(GL_QUADS); glVertex2d(x, y+height+2*b); glVertex2d(x+width+2*b, y+height+2*b); glVertex2d(x+width+2*b, y); glVertex2d(x, y); glEnd(); glDisable(GL_BLEND); glColor3f(0, 0, 0); draw_text(x+b, y+b+7, text); }
static duk_ret_t js_Font_drawZoomedText(duk_context* ctx) { int x = duk_require_int(ctx, 0); int y = duk_require_int(ctx, 1); float scale = duk_require_number(ctx, 2); const char* text = duk_to_string(ctx, 3); ALLEGRO_BITMAP* bitmap; font_t* font; color_t mask; int text_w, text_h; duk_push_this(ctx); font = duk_require_sphere_obj(ctx, -1, "Font"); duk_get_prop_string(ctx, -1, "\xFF" "color_mask"); mask = duk_require_sphere_color(ctx, -1); duk_pop(ctx); duk_pop(ctx); if (!screen_is_skipframe(g_screen)) { text_w = get_text_width(font, text); text_h = get_font_line_height(font); bitmap = al_create_bitmap(text_w, text_h); al_set_target_bitmap(bitmap); draw_text(font, mask, 0, 0, TEXT_ALIGN_LEFT, text); al_set_target_backbuffer(screen_display(g_screen)); al_draw_scaled_bitmap(bitmap, 0, 0, text_w, text_h, x, y, text_w * scale, text_h * scale, 0x0); al_destroy_bitmap(bitmap); } return 0; }
void ZoomBar::create_objects() { int x = 3; int y = get_h() / 2 - mwindow->theme->get_image_set("zoombar_menu", 0)[0]->get_h() / 2; draw_top_background(get_parent(), 0, 0, get_w(), get_h()); sample_zoom = new SampleZoomPanel(mwindow, this, x, y); sample_zoom->set_menu_images(mwindow->theme->get_image_set("zoombar_menu", 0)); sample_zoom->set_tumbler_images(mwindow->theme->get_image_set("zoombar_tumbler", 0)); sample_zoom->create_objects(); x += sample_zoom->get_w(); amp_zoom = new AmpZoomPanel(mwindow, this, x, y); amp_zoom->set_menu_images(mwindow->theme->get_image_set("zoombar_menu", 0)); amp_zoom->set_tumbler_images(mwindow->theme->get_image_set("zoombar_tumbler", 0)); amp_zoom->create_objects(); x += amp_zoom->get_w(); track_zoom = new TrackZoomPanel(mwindow, this, x, y); track_zoom->set_menu_images(mwindow->theme->get_image_set("zoombar_menu", 0)); track_zoom->set_tumbler_images(mwindow->theme->get_image_set("zoombar_tumbler", 0)); track_zoom->create_objects(); x += track_zoom->get_w() + 10; #define DEFAULT_TEXT "000.00 - 000.00" add_subwindow(auto_zoom_popup = new AutoZoomPopup( mwindow, this, x, y, get_text_width(MEDIUMFONT, DEFAULT_TEXT) + 20)); auto_zoom_popup->create_objects(); x += auto_zoom_popup->get_w() + 5; // add_subwindow(auto_zoom_text = new BC_Title( // x, // get_h() / 2 - BC_Title::calculate_h(this, "0") / 2, // DEFAULT_TEXT)); // x += auto_zoom_text->get_w() + 5; add_subwindow(auto_zoom = new AutoZoom(mwindow, this, x, y)); update_autozoom(); x += auto_zoom->get_w() + 5; add_subwindow(from_value = new FromTextBox(mwindow, this, x, y)); x += from_value->get_w() + 5; add_subwindow(length_value = new LengthTextBox(mwindow, this, x, y)); x += length_value->get_w() + 5; add_subwindow(to_value = new ToTextBox(mwindow, this, x, y)); x += to_value->get_w() + 5; update_formatting(from_value); update_formatting(length_value); update_formatting(to_value); add_subwindow(playback_value = new BC_Title(x, 100, _("--"), MEDIUMFONT, RED)); add_subwindow(zoom_value = new BC_Title(x, 100, _("--"), MEDIUMFONT, BLACK)); update(); }
void draw_text(const font_t* font, color_t color, int x, int y, text_align_t alignment, const char* text) { bool is_draw_held; int cp; if (alignment == TEXT_ALIGN_CENTER) x -= get_text_width(font, text) / 2; else if (alignment == TEXT_ALIGN_RIGHT) x -= get_text_width(font, text); is_draw_held = al_is_bitmap_drawing_held(); al_hold_bitmap_drawing(true); while ((cp = *text++) != '\0') { draw_image_masked(font->glyphs[cp].image, color, x, y); x += font->glyphs[cp].width; } al_hold_bitmap_drawing(is_draw_held); }
void GraphicGUI::create_objects() { int margin = plugin->get_theme()->widget_border; int x = get_text_width(SMALLFONT, "-00") + LINE_W4 + margin; int y = margin; int freq_h = get_text_height(SMALLFONT) + LINE_W4; add_subwindow(canvas = new GraphicCanvas(plugin, this, x, y, get_w() - x - margin, get_h() - // BC_Pot::calculate_h() - BC_TextBox::calculate_h(this, MEDIUMFONT, 1, 1) - margin * 3 - y - freq_h)); y += canvas->get_h() + freq_h + margin; int x1 = x; int y1 = y; add_subwindow(freq_title = new BC_Title(x, y, "Frequency:")); x += freq_title->get_w() + margin; add_subwindow(freq_text = new FreqTextBox(plugin, this, x, y, 100)); x += freq_text->get_w() + margin; add_subwindow(level_title = new BC_Title(x, y, "Level:")); x += level_title->get_w() + margin; add_subwindow(value_text = new ValueTextBox(plugin, this, x, y, 100)); x += value_text->get_w() + margin; add_subwindow(reset = new GraphicReset(plugin, this, x, y)); x += reset->get_w() + margin; // x = x1; // y += value_text->get_h() + margin; add_subwindow(size_title = new BC_Title(x, y, "Window size:")); x += size_title->get_w() + margin; add_subwindow(size = new GraphicSize(this, plugin, x, y)); size->create_objects(); size->update(plugin->config.window_size); x += size->get_w() + margin; // add_subwindow(title = new BC_Title(x, y, "Wetness:")); // x += title->get_w() + margin; // add_subwindow(wetness = new GraphicWetness(this, plugin, // x, // y)); draw_ticks(); update_canvas(); show_window(); }
/** * Render the menu to the screen. * * @param[in,out] world A reference to the world structure containing entities to render. * @param[in,out] surface Surface player is being rendered to. * * @designer Jordan Marling * * @author Jordan Marling * @date March 12s, 2024 */ void render_menu_system(World *world, SDL_Surface *surface) { unsigned int entity; RenderPlayerComponent *renderPlayer; PositionComponent *position; TextFieldComponent *text; SDL_Rect menu_rect; for(entity = 0; entity < MAX_ENTITIES; entity++){ if (IN_THIS_COMPONENT(world->mask[entity], SYSTEM_MASK | COMPONENT_MENU_ITEM)) { position = &(world->position[entity]); renderPlayer = &(world->renderPlayer[entity]); menu_rect.x = position->x; menu_rect.y = position->y; menu_rect.w = renderPlayer->width; menu_rect.h = renderPlayer->height; if (IN_THIS_COMPONENT(world->mask[entity], COMPONENT_BUTTON)) { if (world->button[entity].hovered) { menu_rect.x -= 5; menu_rect.y -= 5; menu_rect.w += 10; menu_rect.h += 10; } } SDL_BlitScaled(renderPlayer->playerSurface, NULL, surface, &menu_rect); //check if a textbox. if (IN_THIS_COMPONENT(world->mask[entity], COMPONENT_TEXTFIELD)) { text = &(world->text[entity]); menu_rect.x += 10; menu_rect.y += 8; //TODO: Store the text in a component instead of creating it every frame. //Perhaps we should store it in the renderPlayer component and draw the //textbox if it has a text field component? SDL_BlitSurface(draw_text(text->text, MENU_FONT), NULL, surface, &menu_rect); if (text->focused) { menu_rect.x += get_text_width(text->text, MENU_FONT) + 1; SDL_BlitSurface(ibeam, NULL, surface, &menu_rect); } } } } }
int text_entry::get_caret_offset_from_left() const { ASSERT(_caret_pos <= uint_to_int(_text.length())); int caret_pos_in_visible_text = _caret_pos - _visible_pos; if (caret_pos_in_visible_text <= 0) { return 0; } std::wstring visible_text = std::wstring(_text, _visible_pos, caret_pos_in_visible_text); raw_text_to_visible_text(visible_text); return float_to_int(std::ceil(get_text_width(visible_text))); }
static duk_ret_t js_Font_getStringWidth(duk_context* ctx) { const char* text = duk_to_string(ctx, 0); font_t* font; duk_push_this(ctx); font = duk_require_sphere_obj(ctx, -1, "Font"); duk_pop(ctx); duk_push_int(ctx, get_text_width(font, text)); return 1; }
static duk_ret_t js_Font_getStringWidth(duk_context* ctx) { const char* text = duk_to_string(ctx, 0); font_t* font; duk_push_this(ctx); duk_get_prop_string(ctx, -1, "\xFF" "ptr"); font = duk_get_pointer(ctx, -1); duk_pop(ctx); duk_pop(ctx); duk_push_int(ctx, get_text_width(font, text)); return 1; }
int View::measure_scale_labels() { int result = 0; for (int i = 0; i <= scale_numticks+1; i++) { double value = range_min + (double) i * (range_max - range_min) / (scale_numticks+1); if (fabs(value) < 1e-8) value = 0.0; char text[50]; sprintf(text, scale_fmt, value); int w = get_text_width(text); if (w > result) result = w; } return result; }
void Font::draw(Renderer *renderer, const std::string& text, const Vector& pos_, FontAlignment alignment, DrawingEffect drawing_effect, Color color, float alpha) const { float x = pos_.x; float y = pos_.y; std::string::size_type last = 0; for(std::string::size_type i = 0;; ++i) { if (text[i] == '\n' || i == text.size()) { std::string temp = text.substr(last, i - last); // calculate X positions based on the alignment type Vector pos = Vector(x, y); if(alignment == ALIGN_CENTER) pos.x -= get_text_width(temp) / 2; else if(alignment == ALIGN_RIGHT) pos.x -= get_text_width(temp); // Cast font position to integer to get a clean drawing result and // no blurring as we would get with subpixel positions pos.x = static_cast<int>(pos.x); draw_text(renderer, temp, pos, drawing_effect, color, alpha); if (i == text.size()) break; y += char_height + 2; last = i + 1; } } }
void RecordMonitorGUI:: display_video_text(int x, int y, const char *text, int font, int bg_color, int color, int alpha, double secs, double scale) { lock_window("RecordMonitorGUI::display_text"); set_font(font); int ch = get_text_height(font); int h = get_text_height(font,text) + ch/2; int w = get_text_width(font, text) + ch; BC_Pixmap pixmap(this, w, h); set_opaque(); set_color(bg_color); draw_box(0, 0, w, h, &pixmap); set_color(color); draw_text(ch/2, ch, text, strlen(text), &pixmap); BC_Bitmap bitmap(this, w, h, BC_RGB888, 0); VFrame in(&bitmap, w, h, BC_RGB888, -1); Drawable drawable = pixmap.get_pixmap(); bitmap.read_drawable(drawable, 0, 0, &in); unlock_window(); record->display_vframe(&in, x, y, alpha, secs, scale); }
int SynthNote::draw_face(int flash, int flush) { BC_Toggle::draw_face(0, 0); static const char *titles[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" }; const char *text = titles[number % (sizeof(titles) / sizeof(char*))]; char string[BCTEXTLEN]; sprintf(string, "%s%d", text, number / 12); //printf("SynthNote::draw_face %d %d %d %d %s\n", __LINE__, number, get_w(), get_h(), text); if(text[1] == '#') { } else { set_color(BLACK); draw_text(get_w() / 2 - get_text_width(MEDIUMFONT, string) / 2, get_h() - get_text_height(MEDIUMFONT, string) - window->synth->get_theme()->widget_border, string); } if(flash) this->flash(0); if(flush) this->flush(); return 0; }
void ParametricWindow::create_objects() { int y = 35; SET_TRACE add_subwindow(new BC_Title(X1, 10, _("Freq"))); add_subwindow(new BC_Title(X2, 10, _("Qual"))); add_subwindow(new BC_Title(X3, 10, _("Level"))); add_subwindow(new BC_Title(X4, 10, _("Mode"))); for(int i = 0; i < BANDS; i++) { bands[i] = new ParametricBandGUI(plugin, this, 10, y, i); bands[i]->create_objects(); y += 50; } SET_TRACE BC_Title *title; int x = plugin->get_theme()->widget_border; add_subwindow(title = new BC_Title(x, y + 10, _("Wetness:"))); x += title->get_w() + plugin->get_theme()->widget_border; add_subwindow(wetness = new ParametricWetness(plugin, x, y)); x += wetness->get_w() + plugin->get_theme()->widget_border; add_subwindow(title = new BC_Title(x, y + 10, _("Window:"))); x += title->get_w() + plugin->get_theme()->widget_border; add_subwindow(size = new ParametricSize(this, plugin, x, y + 10)); size->create_objects(); size->update(plugin->config.window_size); y += 50; int canvas_x = 30; int canvas_y = y; int canvas_w = get_w() - canvas_x - 10; int canvas_h = get_h() - canvas_y - 30; add_subwindow(canvas = new BC_SubWindow(canvas_x, canvas_y, canvas_w, canvas_h, BLACK)); SET_TRACE // Draw canvas titles set_font(SMALLFONT); #define MAJOR_DIVISIONS 4 #define MINOR_DIVISIONS 5 for(int i = 0; i <= MAJOR_DIVISIONS; i++) { int y1 = canvas_y + canvas_h - i * (canvas_h / MAJOR_DIVISIONS) - 2; int y2 = y1 + 3; int x1 = canvas_x - 25; int x2 = canvas_x - 10; int x3 = canvas_x - 2; char string[BCTEXTLEN]; if(i == 0) sprintf(string, "oo"); else sprintf(string, "%d", i * 5 - 5); set_color(BLACK); draw_text(x1 + 1, y2 + 1, string); draw_line(x2 + 1, y1 + 1, x3 + 1, y1 + 1); set_color(RED); draw_text(x1, y2, string); draw_line(x2, y1, x3, y1); if(i < MAJOR_DIVISIONS) { for(int j = 1; j < MINOR_DIVISIONS; j++) { int y3 = y1 - j * (canvas_h / MAJOR_DIVISIONS) / MINOR_DIVISIONS; int x4 = x3 - 5; set_color(BLACK); draw_line(x4 + 1, y3 + 1, x3 + 1, y3 + 1); set_color(RED); draw_line(x4, y3, x3, y3); } } } SET_TRACE #undef MAJOR_DIVISIONS #define MAJOR_DIVISIONS 5 for(int i = 0; i <= MAJOR_DIVISIONS; i++) { int freq = Freq::tofreq(i * TOTALFREQS / MAJOR_DIVISIONS); int x1 = canvas_x + i * canvas_w / MAJOR_DIVISIONS; int y1 = canvas_y + canvas_h + 20; char string[BCTEXTLEN]; sprintf(string, "%d", freq); int x2 = x1 - get_text_width(SMALLFONT, string); int y2 = y1 - 10; int y3 = y2 - 5; int y4 = canvas_y + canvas_h; set_color(BLACK); draw_text(x2 + 1, y1 + 1, string); draw_line(x1 + 1, y4 + 1, x1 + 1, y2 + 1); set_color(RED); draw_text(x2, y1, string); draw_line(x1, y4, x1, y2); if(i < MAJOR_DIVISIONS) { #undef MINOR_DIVISIONS #define MINOR_DIVISIONS 5 for(int j = 0; j < MINOR_DIVISIONS; j++) { int x3 = (int)(x1 + (canvas_w / MAJOR_DIVISIONS) - exp(-(double)j * 0.7) * (canvas_w / MAJOR_DIVISIONS)); set_color(BLACK); draw_line(x3 + 1, y4 + 1, x3 + 1, y3 + 1); set_color(RED); draw_line(x3, y4, x3, y3); } } } SET_TRACE update_canvas(); show_window(); SET_TRACE }
int AboutPrefs::create_objects() { int x, y; BC_Resources *resources = BC_WindowBase::get_resources(); // add_subwindow(new BC_Title(mwindow->theme->preferencestitle_x, // mwindow->theme->preferencestitle_y, // _("About"), // LARGEFONT, // resources->text_default)); x = mwindow->theme->preferencesoptions_x; y = mwindow->theme->preferencesoptions_y + get_text_height(LARGEFONT); set_font(LARGEFONT); set_color(resources->text_default); draw_text(x, y, PROGRAM_NAME " " CINELERRA_VERSION); y += get_text_height(LARGEFONT); set_font(MEDIUMFONT); draw_text(x, y, COPYRIGHTTEXT1 #if defined(COPYRIGHTTEXT2) "\n" COPYRIGHTTEXT2 #endif #if defined(REPOMAINTXT) "\n" REPOMAINTXT #endif ); y += get_text_height(MEDIUMFONT) * 4; char versions[BCTEXTLEN]; sprintf(versions, _("Quicktime version %d.%d.%d (%s)\n" "Libmpeg3 version %d.%d.%d\n"), quicktime_major(), quicktime_minor(), quicktime_release(), FFMPEG_EXTERNALTEXT, mpeg3_major(), mpeg3_minor(), mpeg3_release()); draw_text(x, y, versions); y += get_text_height(MEDIUMFONT) * 3; set_font(LARGEFONT); draw_text(x, y, "Credits:"); y += get_text_height(LARGEFONT); set_font(MEDIUMFONT); char credits[BCTEXTLEN]; sprintf(credits, "Jack Crossfire\n" "Richard Baverstock\n" "Karl Bielefeldt\n" "Kevin Brosius\n" "Jean-Luc Coulon\n" "Jean-Michel POURE\n" "Jerome Cornet\n" "Pierre Marc Dumuid\n" "Alex Ferrer\n" "Jan Gerber\n" "Koen Muylkens\n" "Stefan de Konink\n" "Nathan Kurz\n" "Greg Mekkes\n" "Eric Seigne\n" "Joe Stewart\n" "Dan Streetman\n" #ifdef X_HAVE_UTF8_STRING "Gustavo Iñiguez\n" #else "Gustavo I\361iguez\n" #endif "Johannes Sixt\n" "Mark Taraba\n" "Andraz Tori\n" "Jonas Wulff\n" "David Arendt\n" ); draw_text(x, y, credits); int x_indented; x_indented = x + get_text_width(MEDIUMFONT, "Pierre Marc Dumuid") + 20; char credits_cont1[BCTEXTLEN]; sprintf(credits_cont1, #ifdef X_HAVE_UTF8_STRING "Einar Rünkaru\n" #else "Einar R\374nkaru\n" #endif "Monty Montgomery\n" ); draw_text(x_indented, y, credits_cont1); y = get_h() - 135; set_font(LARGEFONT); draw_text(x, y, "License:"); y += get_text_height(LARGEFONT); set_font(MEDIUMFONT); char license3[BCTEXTLEN]; sprintf(license3, _( "This program is free software; you can redistribute it and/or modify it under the terms\n" "of the GNU General Public License as published by the Free Software Foundation; either version\n" "2 of the License, or (at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;\n" "without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n" "PURPOSE. See the GNU General Public License for more details.\n" "\n")); draw_text(x, y, license3); x = get_w() - mwindow->theme->about_bg->get_w() - 10; y = mwindow->theme->preferencesoptions_y; BC_Pixmap *temp_pixmap = new BC_Pixmap(this, mwindow->theme->about_bg, PIXMAP_ALPHA); draw_pixmap(temp_pixmap, x, y); delete temp_pixmap; x += mwindow->theme->about_bg->get_w() + 10; y += get_text_height(LARGEFONT) * 2; flash(); flush(); return 0; }
int hdc_with_font::get_text_width(const string& str) { return get_text_width(to_wstring(str)); }
wraptext_t* word_wrap_text(const font_t* font, const char* text, int width) { char* buffer = NULL; int glyph_width; int line_idx; int line_width; int max_lines = 10; char* line_buffer; char* new_buffer; size_t pitch; int space_width = get_text_width(font, " "); char* string = NULL; char* word; wraptext_t* wraptext; if (!(wraptext = calloc(1, sizeof(wraptext_t)))) goto on_error; // allocate initial buffer get_font_metrics(font, &glyph_width, NULL, NULL); pitch = glyph_width > 0 ? width / glyph_width + 2 : width; if (!(buffer = malloc(max_lines * pitch))) goto on_error; // run through string one word at a time, wrapping as necessary line_buffer = buffer; line_buffer[0] = '\0'; line_idx = 0; line_width = 0; string = strdup(text); word = strtok(string, " "); while (word != NULL) { line_width += get_text_width(font, word); if (line_width > width) { // time for a new line? if (++line_idx >= max_lines) { // enlarge the buffer? max_lines *= 2; if (!(new_buffer = realloc(buffer, max_lines * pitch))) goto on_error; buffer = new_buffer; line_buffer = buffer + line_idx * pitch; } else line_buffer += pitch; line_width = get_text_width(font, word); line_buffer[0] = '\0'; } strcat(line_buffer, word); word = strtok(NULL, " "); if (word != NULL) { strcat(line_buffer, " "); line_width += space_width; } } free(string); wraptext->num_lines = line_idx + 1; wraptext->buffer = buffer; wraptext->pitch = pitch; return wraptext; on_error: free(string); free(buffer); free(wraptext); return NULL; }
void OrderView::on_display() { set_ortho_projection(); glDisable(GL_TEXTURE_1D); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); // transform all vertices ord.lock_data(); int i, nv = ord.get_num_vertices(); double3* vert = ord.get_vertices(); double2* tvert = malloc_with_check<double2>(nv); for (i = 0; i < nv; i++) { tvert[i][0] = transform_x(vert[i][0]); tvert[i][1] = transform_y(vert[i][1]); } // draw all triangles int3* tris = ord.get_triangles(); glBegin(GL_TRIANGLES); for (i = 0; i < ord.get_num_triangles(); i++) { const float* color = order_colors[(int)vert[tris[i][0]][2]]; glColor3f(color[0], color[1], color[2]); glVertex2d(tvert[tris[i][0]][0], tvert[tris[i][0]][1]); glVertex2d(tvert[tris[i][1]][0], tvert[tris[i][1]][1]); glVertex2d(tvert[tris[i][2]][0], tvert[tris[i][2]][1]); } glEnd(); // draw all edges if (pal_type == 0) glColor3f(0.4f, 0.4f, 0.4f); else if (pal_type == 1) glColor3f(1.0f, 1.0f, 1.0f); else glColor3f(0.0f, 0.0f, 0.0f); glBegin(GL_LINES); int2* edges = ord.get_edges(); for (i = 0; i < ord.get_num_edges(); i++) { glVertex2d(tvert[edges[i][0]][0], tvert[edges[i][0]][1]); glVertex2d(tvert[edges[i][1]][0], tvert[edges[i][1]][1]); } glEnd(); // draw labels if (b_orders) { int* lvert; char** ltext; double2* lbox; int nl = ord.get_labels(lvert, ltext, lbox); for (i = 0; i < nl; i++) if (lbox[i][0] * scale > get_text_width(ltext[i]) && lbox[i][1] * scale > 13) { //color = get_palette_color((vert[lvert[i]][2] - 1) / 9.0); const float* color = order_colors[(int)vert[lvert[i]][2]]; if ((color[0] * 0.39f + color[1] * 0.50f + color[2] * 0.11f) > 0.5f) glColor3f(0, 0, 0); else glColor3f(1, 1, 1); draw_text(tvert[lvert[i]][0], tvert[lvert[i]][1], ltext[i], 0); } } free_with_check(tvert); ord.unlock_data(); }
void GraphicGUI::draw_ticks() { int x = canvas->get_x() - 5 - get_text_width(SMALLFONT, "-00"); int y = canvas->get_y() - 1; int x1 = canvas->get_x() - LINE_W3; int x2 = canvas->get_x() - LINE_W2; int x3 = canvas->get_x() - LINE_W1; char string[BCTEXTLEN]; // Amplitude set_font(SMALLFONT); int major_division = canvas->get_h() / (MAJOR_DIVISIONS - 1); for(int i = 0; i < MAJOR_DIVISIONS; i++) { int current_db = (MAJOR_DIVISIONS - 1 - i) * (MAX_DB - MIN_DB) / (MAJOR_DIVISIONS - 1) + MIN_DB; if(current_db == MIN_DB) sprintf(string, "oo"); else if(current_db <= 0.0) sprintf(string, "%d", current_db); else sprintf(string, "+%d", current_db); set_color(BLACK); int y1 = y + 1 + i * canvas->get_h() / (MAJOR_DIVISIONS - 1); int x4 = canvas->get_x() - LINE_W4 - get_text_width(SMALLFONT, string); draw_text(x4 + 1, y1 + get_text_ascent(SMALLFONT) / 2 + 1, string); draw_line(x1 + 1, y1 + 1, x3 + 1, y1 + 1); set_color(RED); draw_text(x4, y1 + get_text_ascent(SMALLFONT) / 2, string); draw_line(x1, y1, x3, y1); if(i < MAJOR_DIVISIONS - 1) { for(int j = 0; j < MINOR_DIVISIONS; j++) { int y2 = y1 + j * major_division / MINOR_DIVISIONS; set_color(BLACK); draw_line(x2 + 1, y2 + 1, x3 + 1, y2 + 1); set_color(RED); draw_line(x2, y2, x3, y2); } } } // Frequency for(int i = 0; i <= MAJOR_DIVISIONS; i++) { int freq = Freq::tofreq(i * TOTALFREQS / MAJOR_DIVISIONS); char string[BCTEXTLEN]; x1 = canvas->get_x() + i * canvas->get_w() / MAJOR_DIVISIONS; int y1 = canvas->get_y() + canvas->get_h() + LINE_W1 - 1; sprintf(string, "%d", freq); int x2 = x1 - get_text_width(SMALLFONT, string); int y2 = canvas->get_y() + canvas->get_h() + LINE_W2 - 1; int y3 = canvas->get_y() + canvas->get_h() + LINE_W3 - 1; int y4 = canvas->get_y() + canvas->get_h() + get_text_height(SMALLFONT) + LINE_W4 - 1; set_color(BLACK); draw_text(x2 + 1, y4 + 1, string); draw_line(x1 + 1, y3 + 1, x1 + 1, y1 + 1); set_color(RED); draw_text(x2, y4, string); draw_line(x1, y3, x1, y1); if(i < MAJOR_DIVISIONS) { for(int j = 0; j < MINOR_DIVISIONS; j++) { int x3 = (int)(x1 + (canvas->get_w() / MAJOR_DIVISIONS) - exp(-(double)j * 0.7) * (canvas->get_w() / MAJOR_DIVISIONS)); set_color(BLACK); draw_line(x3 + 1, y2 + 1, x3 + 1, y1 + 1); set_color(RED); draw_line(x3, y2, x3, y1); } } } }
void stretch_tabstops(sptr_t edit, int block_start_linenum, int block_nof_lines, int max_tabs) { int l, t; et_line* lines = (et_line*)_alloca(sizeof (et_line) * block_nof_lines); memset(lines,0,sizeof (et_line) * block_nof_lines); int new_buffer_size = sizeof (et_tabstop) * __max(1,block_nof_lines * max_tabs); if (new_buffer_size > grid_buffer_size) { et_tabstop* new_buffer = (et_tabstop*)realloc(grid_buffer,new_buffer_size); if (new_buffer == NULL) { return; } grid_buffer = new_buffer; grid_buffer_size = new_buffer_size; } memset(grid_buffer,0,new_buffer_size); et_tabstop** grid = (et_tabstop**)_alloca(sizeof (et_tabstop*) * block_nof_lines); for (l = 0; l < block_nof_lines; l++) { grid[l] = grid_buffer + (l * max_tabs); } // get width of text in cells for (l = 0; l < block_nof_lines; l++) // for each line { int text_width_in_tab = 0; int current_line_num = block_start_linenum + l; int current_tab_num = 0; bool cell_empty = true; int current_pos = call_edit(edit,SCI_POSITIONFROMLINE,current_line_num); int cell_start = current_pos; unsigned char current_char = (unsigned char)call_edit(edit,SCI_GETCHARAT,current_pos); bool current_char_ends_line = is_line_end(edit,current_pos); // maybe change this to search forwards for tabs/newlines while (current_char != '\0') { if (current_char_ends_line) { grid[l][current_tab_num].ends_in_tab = false; text_width_in_tab = 0; break; } else if (current_char == '\t') { if (!cell_empty) { text_width_in_tab = get_text_width(edit,cell_start,current_pos); } grid[l][current_tab_num].ends_in_tab = true; grid[l][current_tab_num].text_width_pix = calc_tab_width(text_width_in_tab); current_tab_num++; lines[l].num_tabs++; text_width_in_tab = 0; cell_empty = true; } else { if (cell_empty) { cell_start = current_pos; cell_empty = false; } } current_pos = call_edit(edit,SCI_POSITIONAFTER,current_pos); current_char = (unsigned char)call_edit(edit,SCI_GETCHARAT,current_pos); current_char_ends_line = is_line_end(edit,current_pos); } } // find columns blocks and stretch to fit the widest cell for (t = 0; t < max_tabs; t++) // for each column { bool starting_new_block = true; int first_line_in_block = 0; int max_width = 0; for (l = 0; l < block_nof_lines; l++) // for each line { if (starting_new_block) { starting_new_block = false; first_line_in_block = l; max_width = 0; } if (grid[l][t].ends_in_tab) { grid[l][t].widest_width_pix = &(grid[first_line_in_block][t].text_width_pix); // point widestWidthPix at first if (grid[l][t].text_width_pix > max_width) { max_width = grid[l][t].text_width_pix; grid[first_line_in_block][t].text_width_pix = max_width; } } else // end column block { starting_new_block = true; } } } std::vector<int> tab_array; // set tabstops for (l = 0; l < block_nof_lines; l++) // for each line { int current_line_num = block_start_linenum + l; int acc_tabstop = 0; tab_array.resize(lines[l].num_tabs + 1); tab_array[lines[l].num_tabs] = 0; for (t = 0; t < lines[l].num_tabs; t++) { if (grid[l][t].widest_width_pix != NULL) { acc_tabstop += *(grid[l][t].widest_width_pix); tab_array[t] = acc_tabstop; } else { tab_array[t] = 0; } } call_edit(edit,SCI_SETTABSTOPS,current_line_num,(LONG_PTR)&(tab_array.at(0))); } }
void draw_text(const font_t* font, color_t color, int x, int y, text_align_t alignment, const char* text) { uint8_t ch_byte; uint32_t cp; int tab_width; uint32_t utf8state; if (alignment == TEXT_ALIGN_CENTER) x -= get_text_width(font, text) / 2; else if (alignment == TEXT_ALIGN_RIGHT) x -= get_text_width(font, text); tab_width = font->glyphs[' '].width * 3; al_hold_bitmap_drawing(true); for (;;) { utf8state = UTF8_ACCEPT; while (utf8decode(&utf8state, &cp, ch_byte = *text++) > UTF8_REJECT); if (utf8state == UTF8_REJECT && ch_byte == '\0') --text; // don't eat NUL terminator cp = cp == 0x20AC ? 128 : cp == 0x201A ? 130 : cp == 0x0192 ? 131 : cp == 0x201E ? 132 : cp == 0x2026 ? 133 : cp == 0x2020 ? 134 : cp == 0x2021 ? 135 : cp == 0x02C6 ? 136 : cp == 0x2030 ? 137 : cp == 0x0160 ? 138 : cp == 0x2039 ? 139 : cp == 0x0152 ? 140 : cp == 0x017D ? 142 : cp == 0x2018 ? 145 : cp == 0x2019 ? 146 : cp == 0x201C ? 147 : cp == 0x201D ? 148 : cp == 0x2022 ? 149 : cp == 0x2013 ? 150 : cp == 0x2014 ? 151 : cp == 0x02DC ? 152 : cp == 0x2122 ? 153 : cp == 0x0161 ? 154 : cp == 0x203A ? 155 : cp == 0x0153 ? 156 : cp == 0x017E ? 158 : cp == 0x0178 ? 159 : cp; cp = utf8state == UTF8_ACCEPT ? cp < (uint32_t)font->num_glyphs ? cp : 0x1A : 0x1A; if (cp == '\0') break; else if (cp == '\t') x += tab_width; else { draw_image_masked(font->glyphs[cp].image, color, x, y); x += font->glyphs[cp].width; } } al_hold_bitmap_drawing(false); }
/** @brief create pixmaps with the specified name if it is available, otherwise use a default name @return void **/ void create_frame_name(Display* display, struct Popup_menu *window_menu, struct Frame *temp , struct Themes *themes, struct Atoms *atoms) { char untitled[] = "noname"; //struct Frame temp = *frame; Screen* screen = DefaultScreenOfDisplay(display); int black = BlackPixelOfScreen(screen); /* Destroy/Free old title if it had one */ free_frame_name(temp); { /* Recover EWMH UTF8 name first. If none exists, get the ICCCM ASCII name */ /* If this succeeds, previous names will be freed if they exists later on */ Atom ret_type; int ret_format; unsigned long ret_nitems; unsigned long ret_trailing_bytes; temp->window_name = NULL; if((XGetWindowProperty (display, temp->framed_window, atoms->name, (long)0, (long)MAX_WM_NAME_LENGTH , False, atoms->utf8 , &ret_type, &ret_format, &ret_nitems, &ret_trailing_bytes , (unsigned char **)&temp->window_name ) != Success) || temp->window_name == NULL) { //Try and get the non EWMH name if(!XFetchName(display, temp->framed_window, &temp->window_name)) { //Generate a blank name. printf("Warning: unnamed window\n"); XStoreName(display, temp->framed_window, untitled); XFlush(display); XFetchName(display, temp->framed_window, &temp->window_name); XFlush(display); } } } /* if(temp->window_name == NULL && frame->window_name != NULL && strcmp(frame->window_name, untitled) == 0) { //it was null and already has the name from untitled above. return; } else if( (temp->window_name != NULL && frame->window_name != NULL ) && (strcmp(temp->window_name, frame->window_name) == 0)) { XFree(temp->window_name); //skip this if the name hasn't changed return; } */ if(!temp->menu.item) { temp->menu.item = XCreateSimpleWindow(display , window_menu->widgets[popup_menu_parent].widget , themes->popup_menu[l_edge].w, 0 , XWidthOfScreen(screen), themes->popup_menu[menu_item_mid].h , 0, black, black); for(int i = 0; i <= inactive; i++) { temp->menu.state[i] = XCreateSimpleWindow(display , temp->menu.item , 0, 0 , XWidthOfScreen(screen), themes->popup_menu[menu_item_mid].h , 0, black, black); } XSelectInput(display, temp->menu.item, ButtonReleaseMask | EnterWindowMask | LeaveWindowMask); } temp->menu.width = get_text_width(display, temp->window_name, &themes->font_theme[active]); //create corresponding title menu item for this frame for(int i = 0; i <= inactive; i++) { XUnmapWindow(display, temp->menu.state[i]); XUnmapWindow(display, temp->widgets[title_menu_text].state[i]); XFlush(display); //create the title menu item with the windows title create_text_background(display, temp->menu.state[i], temp->window_name , &themes->font_theme[i], themes->popup_menu[menu_item_mid].state_p[i] , XWidthOfScreen(screen), themes->popup_menu[menu_item_mid].h); //TODO make the title for unfocussed windows not bold? create_text_background(display, temp->widgets[title_menu_text].state[i], temp->window_name , &themes->font_theme[active], themes->window_type[temp->theme_type][title_menu_text].state_p[i] , XWidthOfScreen(screen), themes->window_type[temp->theme_type][title_menu_text].h); //If this is mapped here, it might be shown in the wrong workspace, //XMapWindow(display, temp->menu.item); /* Show changes to background pixmaps */ XMapWindow(display, temp->menu.state[i]); XMapWindow(display, temp->widgets[title_menu_text].state[i]); } xcheck_raisewin(display, temp->menu.state[active]); //these are the items for inside the menu //need to create all these windows. { XWindowAttributes attr; XGetWindowAttributes(display, temp->menu.item, &attr); if(attr.map_state != IsUnmapped) { //remap all the state pixmaps XSelectInput(display, temp->menu.item, 0); XSync(display, False); XUnmapWindow(display, temp->menu.item); XSelectInput(display, temp->menu.item, ButtonReleaseMask | EnterWindowMask | LeaveWindowMask); XFlush(display); XMapWindow(display, temp->menu.item); } } XFlush(display); //*frame = temp; }
void PluginAClientWindow::create_objects() { PluginServer *server = plugin->server; char string[BCTEXTLEN]; int current_port = 0; int x = 10; int y = 10; int x2 = 300; int x3 = 335; int title_vmargin = 5; int max_w = 0; const LADSPA_Descriptor *lad_desc = server->lad_descriptor; const LADSPA_PortDescriptor *port_desc = lad_desc->PortDescriptors; int port_count = lad_desc->PortCount; for(int i = 0; i < port_count; i++) { if( !LADSPA_IS_PORT_INPUT(port_desc[i]) ) continue; if( !LADSPA_IS_PORT_CONTROL(port_desc[i]) ) continue; int w = get_text_width(MEDIUMFONT, (char*)lad_desc->PortNames[i]); if(w > max_w) max_w = w; } x2 = max_w + 20; x3 = max_w + 55; for(int i = 0; i < port_count; i++) { if( !LADSPA_IS_PORT_INPUT(port_desc[i]) ) continue; if( !LADSPA_IS_PORT_CONTROL(port_desc[i]) ) continue; const LADSPA_PortRangeHint *lad_hint = &lad_desc->PortRangeHints[i]; LADSPA_PortRangeHintDescriptor hint_desc = lad_hint->HintDescriptor; int use_min = LADSPA_IS_HINT_BOUNDED_BELOW(hint_desc); int use_max = LADSPA_IS_HINT_BOUNDED_ABOVE(hint_desc); sprintf(string, "%s:", lad_desc->PortNames[i]); // printf("PluginAClientWindow::create_objects 1 %s type=%d lower: %d %f upper: %d %f\n", // string, plugin->config.port_type[current_port], // use_min, lad_hint->LowerBound, use_max, lad_hint->UpperBound); switch(plugin->config.port_type[current_port]) { case PluginAClientConfig::PORT_NORMAL: { PluginACLientFLinear *flinear; float min = use_min ? lad_hint->LowerBound : 0; float max = use_max ? lad_hint->UpperBound : 100; add_subwindow(new BC_Title(x, y + title_vmargin, string)); add_subwindow(flinear = new PluginACLientFLinear( plugin, (current_port % 2) ? x2 : x3, y, &plugin->config.port_data[current_port], min, max)); fpots.append(flinear); break; } case PluginAClientConfig::PORT_FREQ_INDEX: { PluginACLientFreq *freq; add_subwindow(new BC_Title(x, y + title_vmargin, string)); add_subwindow(freq = new PluginACLientFreq(plugin, (current_port % 2) ? x2 : x3, y, &plugin->config.port_data[current_port], 0 /* (plugin->config.port_type[current_port] == PluginAClientConfig::PORT_FREQ_INDEX */)); freqs.append(freq); break; } case PluginAClientConfig::PORT_TOGGLE: { PluginACLientToggle *toggle; add_subwindow(new BC_Title(x, y + title_vmargin, string)); add_subwindow(toggle = new PluginACLientToggle(plugin, (current_port % 2) ? x2 : x3, y, &plugin->config.port_data[current_port])); toggles.append(toggle); break; } case PluginAClientConfig::PORT_INTEGER: { PluginACLientILinear *ilinear; float min = use_min ? lad_hint->LowerBound : 0; float max = use_max ? lad_hint->UpperBound : 100; add_subwindow(new BC_Title(x, y + title_vmargin, string)); add_subwindow(ilinear = new PluginACLientILinear( plugin, (current_port % 2) ? x2 : x3, y, &plugin->config.port_data[current_port], (int)min, (int)max)); ipots.append(ilinear); break; } } current_port++; y += 30; //printf("PluginAClientWindow::create_objects 2\n"); } y += 10; sprintf(string, _("Author: %s"), lad_desc->Maker); add_subwindow(new BC_Title(x, y, string)); y += 20; sprintf(string, _("License: %s"), lad_desc->Copyright); add_subwindow(new BC_Title(x, y, string)); show_window(1); }
/** @brief Creates a new workspace, including separators used for stacking windows in different modes and the workspace menu item for the program menu. @return the index of the created workspace **/ int create_workspace(Display *display, struct Workspace_list* workspaces, char *workspace_name, struct Themes *themes) { // Window root = DefaultRootWindow(display); Screen* screen = DefaultScreenOfDisplay(display); int black = BlackPixelOfScreen(screen); // XSetWindowAttributes attributes; struct Workspace *frames; if(workspaces->list == NULL) { workspaces->used_workspaces = 0; workspaces->max_workspaces = 16; workspaces->list = malloc(sizeof(struct Workspace) * workspaces->max_workspaces); if(workspaces->list == NULL) return -1; } else if(workspaces->used_workspaces == workspaces->max_workspaces) { //printf("reallocating, used_workspaces %d, max%d\n", workspaces->used_workspaces, workspaces->max); struct Workspace* temp = NULL; temp = realloc(workspaces->list, sizeof(struct Workspace) * workspaces->max_workspaces * 2); if(temp != NULL) workspaces->list = temp; else { perror("\nError: Not enough available memory\n"); return -1; } workspaces->max_workspaces *= 2; } //the frame list frames is the new workspace frames = &workspaces->list[workspaces->used_workspaces]; frames->workspace_name = workspace_name; frames->states = calloc(sizeof(struct Saved_frame_state), workspaces->max_frames); if(!frames->states) { perror("Error: not enough memory to allocate frame save states in a new workspace"); return -1; } //TODO when a workspace is added to the list, it must also be resized to the width of that list. unsigned int width = workspaces->workspace_menu.inner_width; frames->workspace_menu.item = XCreateSimpleWindow(display , workspaces->workspace_menu.widgets[popup_menu_parent].widget , themes->popup_menu[popup_l_edge].w, themes->popup_menu[popup_t_edge].h , width, themes->popup_menu[menu_item_mid].h , 0, black, black); XSelectInput(display, frames->workspace_menu.item, ButtonReleaseMask | EnterWindowMask | LeaveWindowMask); for(int i = 0; i <= inactive; i++) { //if(themes->popup_menu[menu_item].state_p[i]) frames->workspace_menu.state[i] = XCreateSimpleWindow(display , frames->workspace_menu.item , 0, 0 , XWidthOfScreen(screen), themes->popup_menu[menu_item_mid].h , 0, black, black); create_text_background(display, frames->workspace_menu.state[i], frames->workspace_name , &themes->font_theme[i], themes->popup_menu[menu_item_mid].state_p[i] , themes->popup_menu[menu_item_mid].w, themes->popup_menu[menu_item_mid].h); XMapWindow(display, frames->workspace_menu.state[i]); } XMapWindow(display, frames->workspace_menu.item); frames->workspace_menu.width = get_text_width(display, frames->workspace_name, &themes->font_theme[active]); //Create the frame_list frames->used = 0; frames->max = DEFAULT_STARTING_FRAMES; frames->list = NULL; //this is allocated when we change to this workspace. frames->focus.used = 0; frames->focus.max = 8; //must be divisible by 2 frames->focus.list = malloc(sizeof(struct Focus_list) * frames->focus.max); //ok if it fails. #ifdef SHOW_WORKSPACE printf("Created workspace %d\n", workspaces->used_workspaces); #endif //need to make the existing neutral windows available to new workspaces for(int i = 0; i < workspaces->used_frames; i++) { if(suitable_for_foreign_workspaces(&workspaces->frame_list[i])) { load_initial_states(&frames->states[i], &workspaces->frame_list[i]); } } workspaces->used_workspaces++; XSync(display, False); return workspaces->used_workspaces - 1; }
void SynthWindow::update_notes() { //int octave_w = white_key[0]->get_w() * 7; int white_w = white_key[0]->get_w(); int black_w = black_key[0]->get_w(); int white_w1 = white_w - black_w / 2 - 2; int white_w2 = white_w / 2; int white_w3 = white_w * 2 / 3; int y = 0; int x = 0; y1 = y + white_key[0]->get_h() + 10; y2 = y1 + get_text_height(MEDIUMFONT) + 10; y3 = y2 + get_text_height(MEDIUMFONT) + 10; text_black_margin = black_w / 2 - get_text_width(MEDIUMFONT, "O") / 2; text_white_margin = white_w / 2 - get_text_width(MEDIUMFONT, "O") / 2; //printf("SynthWindow::update_notes %d\n", __LINE__); note_subwindow->clear_box(0, 0, get_w(), get_h()); note_subwindow->set_color(get_resources()->default_text_color); // Add new notes // To get the stacking order: // pass 0 is white keys // pass 1 is black keys int current_title = 0; for(int pass = 0; pass < 2; pass++) { x = -note_scroll->get_position(); for(int i = 0; i < TOTALNOTES; i++) { int octave_note = i % 12; if(!pass) { // White keys switch(octave_note) { case 0: update_whitekey(i, ¤t_title, x, y); break; case 1: x += white_w; break; case 2: update_whitekey(i, ¤t_title, x, y); break; case 3: x += white_w; break; case 4: update_whitekey(i, ¤t_title, x, y); x += white_w; break; case 5: update_whitekey(i, ¤t_title, x, y); break; case 6: x += white_w; break; case 7: update_whitekey(i, ¤t_title, x, y); break; case 8: x += white_w; break; case 9: update_whitekey(i, ¤t_title, x, y); break; case 10: x += white_w; break; case 11: update_whitekey(i, ¤t_title, x, y); x += white_w; break; } } else { // Black keys switch(octave_note) { case 1: update_blackkey(i, ¤t_title, x + white_w2, y); x += white_w; break; case 3: update_blackkey(i, ¤t_title, x + white_w3, y); x += white_w; break; case 4: x += white_w; break; case 6: update_blackkey(i, ¤t_title, x + white_w2, y); x += white_w; break; case 8: update_blackkey(i, ¤t_title, x + white_w1, y); x += white_w; break; case 10: update_blackkey(i, ¤t_title, x + white_w3, y); x += white_w; break; case 11: x += white_w; break; } } } } }
wraptext_t* word_wrap_text(const font_t* font, const char* text, int width) { char* buffer = NULL; uint8_t ch_byte; char* carry; size_t ch_size; uint32_t cp; int glyph_width; bool is_line_end = false; int line_idx; int line_width; int max_lines = 10; char* last_break; char* last_space; char* last_tab; char* line_buffer; size_t line_length; char* new_buffer; size_t pitch; uint32_t utf8state; wraptext_t* wraptext; const char *p, *start; if (!(wraptext = calloc(1, sizeof(wraptext_t)))) goto on_error; // allocate initial buffer get_font_metrics(font, &glyph_width, NULL, NULL); pitch = 4 * (glyph_width > 0 ? width / glyph_width : width) + 3; if (!(buffer = malloc(max_lines * pitch))) goto on_error; if (!(carry = malloc(pitch))) goto on_error; // run through one character at a time, carrying as necessary line_buffer = buffer; line_buffer[0] = '\0'; line_idx = 0; line_width = 0; line_length = 0; memset(line_buffer, 0, pitch); // fill line with NULs p = text; do { utf8state = UTF8_ACCEPT; start = p; while (utf8decode(&utf8state, &cp, ch_byte = *p++) > UTF8_REJECT); if (utf8state == UTF8_REJECT && ch_byte == '\0') --p; // don't eat NUL terminator ch_size = p - start; cp = cp == 0x20AC ? 128 : cp == 0x201A ? 130 : cp == 0x0192 ? 131 : cp == 0x201E ? 132 : cp == 0x2026 ? 133 : cp == 0x2020 ? 134 : cp == 0x2021 ? 135 : cp == 0x02C6 ? 136 : cp == 0x2030 ? 137 : cp == 0x0160 ? 138 : cp == 0x2039 ? 139 : cp == 0x0152 ? 140 : cp == 0x017D ? 142 : cp == 0x2018 ? 145 : cp == 0x2019 ? 146 : cp == 0x201C ? 147 : cp == 0x201D ? 148 : cp == 0x2022 ? 149 : cp == 0x2013 ? 150 : cp == 0x2014 ? 151 : cp == 0x02DC ? 152 : cp == 0x2122 ? 153 : cp == 0x0161 ? 154 : cp == 0x203A ? 155 : cp == 0x0153 ? 156 : cp == 0x017E ? 158 : cp == 0x0178 ? 159 : cp; cp = utf8state == UTF8_ACCEPT ? cp < (uint32_t)font->num_glyphs ? cp : 0x1A : 0x1A; switch (cp) { case '\n': case '\r': // explicit newline if (cp == '\r' && *p == '\n') ++text; // CRLF is_line_end = true; break; case '\t': // tab line_buffer[line_length++] = cp; line_width += get_text_width(font, " "); is_line_end = false; break; case '\0': // NUL terminator is_line_end = line_length > 0; // commit last line on EOT break; default: // default case, copy character as-is memcpy(line_buffer + line_length, start, ch_size); line_length += ch_size; line_width += get_glyph_width(font, cp); is_line_end = false; } if (is_line_end) carry[0] = '\0'; if (line_width > width || line_length >= pitch - 1) { // wrap width exceeded, carry current word to next line is_line_end = true; last_space = strrchr(line_buffer, ' '); last_tab = strrchr(line_buffer, '\t'); last_break = last_space > last_tab ? last_space : last_tab; if (last_break != NULL) // word break (space or tab) found strcpy(carry, last_break + 1); else // no word break, so just carry last character sprintf(carry, "%c", line_buffer[line_length - 1]); line_buffer[line_length - strlen(carry)] = '\0'; } if (is_line_end) { // do we need to enlarge the buffer? if (++line_idx >= max_lines) { max_lines *= 2; if (!(new_buffer = realloc(buffer, max_lines * pitch))) goto on_error; buffer = new_buffer; line_buffer = buffer + line_idx * pitch; } else line_buffer += pitch; memset(line_buffer, 0, pitch); // fill line with NULs // copy carry text into new line line_width = get_text_width(font, carry); line_length = strlen(carry); strcpy(line_buffer, carry); } } while (cp != '\0'); free(carry); wraptext->num_lines = line_idx; wraptext->buffer = buffer; wraptext->pitch = pitch; return wraptext; on_error: free(buffer); free(wraptext); return NULL; }