diff --git a/common/include/fwd-gr.h b/common/include/fwd-gr.h index a330eb0a6..cb19e03ed 100644 --- a/common/include/fwd-gr.h +++ b/common/include/fwd-gr.h @@ -282,6 +282,7 @@ void gr_printt(grs_canvas &, const grs_font &, int x, int y, const char *format, #define gr_uprintf(A1,A2,A3,A4,F,...) dxx_call_printf_checked(gr_printfus,gr_ustring,(A1,A2,A3,A4),(F),##__VA_ARGS__) std::pair gr_get_string_wrap(const grs_font &, const char *s, unsigned limit); void gr_get_string_size(const grs_font &, const char *s, int *string_width, int *string_height, int *average_width); +void gr_get_string_size(const grs_font &, const char *s, int *string_width, int *string_height, int *average_width, const unsigned max_chars_per_line); // From scale.c void scale_bitmap(const grs_bitmap &bp, const array &vertbuf, int orientation, grs_bitmap &); diff --git a/common/include/ntstring.h b/common/include/ntstring.h index 0b53665b3..1f5c3fd56 100644 --- a/common/include/ntstring.h +++ b/common/include/ntstring.h @@ -55,8 +55,6 @@ public: { return copy_if(out_offset, static_cast(i), this->size()); } - template - void copy_if(std::size_t, const ntstring &, std::size_t = 0) = delete; template std::size_t copy_if(std::size_t out_offset, const array &i, std::size_t n = N) { diff --git a/similar/2d/font.cpp b/similar/2d/font.cpp index e07505461..1bd7b6eb4 100644 --- a/similar/2d/font.cpp +++ b/similar/2d/font.cpp @@ -769,6 +769,11 @@ void gr_ustring(grs_canvas &canvas, const grs_font &cv_font, const int x, const } void gr_get_string_size(const grs_font &cv_font, const char *s, int *const string_width, int *const string_height, int *const average_width) +{ + gr_get_string_size(cv_font, s, string_width, string_height, average_width, UINT_MAX); +} + +void gr_get_string_size(const grs_font &cv_font, const char *s, int *const string_width, int *const string_height, int *const average_width, const unsigned max_chars_per_line) { float longest_width=0.0,string_width_f=0.0; unsigned lines = 0; @@ -778,6 +783,7 @@ void gr_get_string_size(const grs_font &cv_font, const char *s, int *const strin return; if (s) { + unsigned remaining_chars_this_line = max_chars_per_line; while (*s) { if (*s == '\n') @@ -792,12 +798,15 @@ void gr_get_string_size(const grs_font &cv_font, const char *s, int *const strin lines += s - os; if (!*s) break; + remaining_chars_this_line = max_chars_per_line; } const auto &result = get_char_width(cv_font, s[0], s[1]); const auto &spacing = result.spacing; string_width_f += spacing; s++; + if (!--remaining_chars_this_line) + break; } } if (string_width) diff --git a/similar/main/mission.cpp b/similar/main/mission.cpp index 2c633f7d4..d76aa03d1 100644 --- a/similar/main/mission.cpp +++ b/similar/main/mission.cpp @@ -79,7 +79,7 @@ using mission_candidate_search_path = array; struct mle : Mission_path { int builtin_hogsize; // if it's the built-in mission, used for determining the version - ntstring mission_name; + ntstring<75> mission_name; #if defined(DXX_BUILD_DESCENT_II) descent_version_type descent_version; // descent 1 or descent 2? #endif @@ -326,7 +326,7 @@ static char *get_value(char *buf) } //reads a line, returns ptr to value of passed parm. returns NULL if none -static char *get_parm_value(PHYSFSX_gets_line_t<80> &buf, const char *parm,PHYSFS_File *f) +static char *get_parm_value(PHYSFSX_gets_line_t<80> &buf, const char *const parm, PHYSFS_File *const f) { if (!PHYSFSX_fgets(buf,f)) return NULL; @@ -740,7 +740,7 @@ static int load_mission(const mle *mission) #endif Current_mission = make_unique(); Current_mission->builtin_hogsize = mission->builtin_hogsize; - Current_mission->mission_name = mission->mission_name; + Current_mission->mission_name.copy_if(mission->mission_name); #if defined(DXX_BUILD_DESCENT_II) Current_mission->descent_version = mission->descent_version; #endif diff --git a/similar/main/newmenu.cpp b/similar/main/newmenu.cpp index 591fbc49e..5ecc62bf5 100644 --- a/similar/main/newmenu.cpp +++ b/similar/main/newmenu.cpp @@ -1912,12 +1912,59 @@ static void listbox_create_structure( listbox *lb) lb->box_w = 0; const auto &&fspacx = FSPACX(); - range_for (auto &i, unchecked_partial_range(lb->item, lb->nitems)) + const auto &&fspacx10 = fspacx(10); + const unsigned max_box_width = SWIDTH - (BORDERX * 2); + unsigned marquee_maxchars = UINT_MAX; + range_for (const auto i, unchecked_partial_range(lb->item, lb->nitems)) { int w; gr_get_string_size(medium3_font, i, &w, nullptr, nullptr); - if ( w > lb->box_w ) - lb->box_w = w + fspacx(10); + w += fspacx10; + if (w > max_box_width) + { + unsigned mmc = 1; + for (;; ++mmc) + { + int w2; + gr_get_string_size(medium3_font, i, &w2, nullptr, nullptr, mmc); + if (w2 > max_box_width) + break; + } + /* mmc is now the shortest initial subsequence that is wider + * than max_box_width. + * + * Next, search for whether any internal subsequences of + * lesser length are also too wide. This can happen if all + * the initial characters are narrow, then characters + * outside the initial subsequence are wide. + */ + for (auto j = i;;) + { + int w2; + gr_get_string_size(medium3_font, j, &w2, nullptr, nullptr, mmc); + if (w2 > max_box_width) + { + /* This subsequence is too long. Reduce the length + * and retry. + */ + if (!--mmc) + break; + } + else + { + /* This subsequence fits. Move to the next + * character. + */ + if (!*++j) + break; + } + } + w = max_box_width; + if (marquee_maxchars > mmc) + marquee_maxchars = mmc; + } + if (lb->box_w < w) + lb->box_w = w; } { @@ -1929,13 +1976,10 @@ static void listbox_create_structure( listbox *lb) } // The box is bigger than we can fit on the screen since at least one string is too long. Check how many chars we can fit on the screen (at least only - MEDIUM*_FONT is variable font!) so we can make a marquee-like effect. - if (lb->box_w + (BORDERX*2) > SWIDTH) + if (marquee_maxchars != UINT_MAX) { - int w; - - const auto box_w = lb->box_w = SWIDTH - (BORDERX*2); - gr_get_string_size(medium3_font, "O", &w, nullptr, nullptr); - lb->marquee = listbox::marquee::allocate(box_w / w); + lb->box_w = max_box_width; + lb->marquee = listbox::marquee::allocate(marquee_maxchars); lb->marquee->lasttime = timer_query(); }