@@ -31,10 +31,14 @@ const int LINES_IN_ITEM_WIN = 8;
31
31
#include < boost/lexical_cast.hpp>
32
32
33
33
typedef struct {
34
- char line[50 ];
35
- } buf_line;
34
+ std::string message;
35
+ int line_count;
36
+ int duplicate_count;
37
+ bool duplicate_overflow;
38
+ } buf_msg;
39
+
40
+ buf_msg text_buffer[TEXT_BUF_LEN];
36
41
37
- buf_line text_buffer[TEXT_BUF_LEN];
38
42
short buf_pointer = 30 ;
39
43
40
44
rectangle status_panel_clip_rect = {11 , 299 , 175 , 495 },item_panel_clip_rect = {11 ,297 ,175 ,463 };
@@ -59,7 +63,7 @@ extern location store_anim_ul;
59
63
extern tessel_ref_t bg[];
60
64
extern short dest_personalities[40 ];
61
65
extern location source_locs[6 ];
62
- extern location dest_locs[40 ] ;
66
+ extern location dest_locs[40 ];
63
67
extern location center;
64
68
65
69
extern cCustomGraphics spec_scen_g;
@@ -963,10 +967,20 @@ short print_terrain(location space) {
963
967
void add_string_to_buf (std::string str) {
964
968
// This is a separate overload instead of using a defaulted parameter so that
965
969
// it can be passed as an argument to various other functions
966
- add_string_to_buf (str, 0 );
970
+ size_t starting_indent = str.find_first_not_of (' ' );
971
+ if (starting_indent != std::string::npos)
972
+ add_string_to_buf (str, starting_indent + 2 );
967
973
}
968
974
969
975
void add_string_to_buf (std::string str, unsigned short indent) {
976
+ if (overall_mode == MODE_STARTUP)
977
+ return ;
978
+ if (str == " " ) return ;
979
+ if (str.find_last_not_of (' ' ) == std::string::npos)
980
+ return ;
981
+
982
+ if (indent > 20 ) indent = 20 ;
983
+
970
984
static bool inited;
971
985
static size_t width;
972
986
static TextStyle buf_style;
@@ -976,100 +990,46 @@ void add_string_to_buf(std::string str, unsigned short indent) {
976
990
buf_style.pointSize = 12 ;
977
991
width = text_area_gworld ().getSize ().x - 5 ;
978
992
}
979
- if (overall_mode == MODE_STARTUP)
980
- return ;
981
-
982
- if (str == " " ) return ;
983
- if (str.find_last_not_of (' ' ) == std::string::npos)
984
- return ;
985
-
986
- if (indent && string_length (str.substr (0 ,str.find_last_not_of (' ' )), buf_style) >= width) {
987
- if (indent > 20 ) indent = 20 ;
988
- size_t split = str.find_last_of (' ' , 49 );
989
- while (string_length (str.substr (0 ,split), buf_style) >= width)
990
- split = str.find_last_of (' ' , split - 1 );
991
- add_string_to_buf (str.substr (0 ,split));
992
- str = str.substr (split);
993
- std::string space (indent, ' ' );
994
- size_t wrap_w = width - string_length (space, buf_style);
995
- while (string_length (str.substr (0 ,str.find_last_not_of (' ' )), buf_style) > wrap_w) {
996
- std::string wrap = space;
997
- split = str.find_last_of (' ' , 49 - indent);
998
- while (string_length (str.substr (0 ,split), buf_style) >= wrap_w)
999
- split = str.find_last_of (' ' , split - 1 );
1000
- wrap += str.substr (0 ,split);
1001
- str = str.substr (split);
1002
- add_string_to_buf (wrap);
1003
- }
1004
- add_string_to_buf (space + str);
1005
- return ;
993
+
994
+ std::string wrapped_str = str;
995
+ int line_count = 1 ;
996
+ int wrapped_idx = 0 ;
997
+ std::string space (indent, ' ' );
998
+ while (string_length (wrapped_str.substr (wrapped_idx, wrapped_str.find_last_not_of (' ' )), buf_style) >= width) {
999
+ size_t split = wrapped_str.find_last_of (' ' );
1000
+ while (string_length (wrapped_str.substr (wrapped_idx, split), buf_style) >= width)
1001
+ split = wrapped_str.find_last_of (' ' , split - 1 );
1002
+
1003
+ wrapped_str[split] = ' \n ' ;
1004
+ wrapped_str.insert (split + 1 , space);
1005
+
1006
+ wrapped_idx = split + 1 + indent;
1007
+ line_count += 1 ;
1006
1008
}
1007
1009
1008
- // Now check if this is a duplicate message
1010
+ // Check if this is a duplicate message
1009
1011
int prev_pointer = buf_pointer - 1 ;
1010
1012
if (prev_pointer < 0 ) prev_pointer = TEXT_BUF_LEN - 1 ;
1011
- size_t last = 0 , new_last = str.find_last_not_of (' ' );
1012
- // Find the last non-space character that matches
1013
- while (last < str.length () && str[last] == text_buffer[prev_pointer].line [last])
1014
- last++;
1015
- while (last > 0 && text_buffer[prev_pointer].line [--last] == ' ' );
1016
- bool is_dup = false ;
1017
- if (last == new_last) {
1018
- size_t num_pos = 0 ;
1019
- enum {begin, f_space, f_lparen, f_x, f_num, f_rparen, err} state = begin;
1020
- for (short i = last; i < 50 && text_buffer[prev_pointer].line [i]; i++) {
1021
- if (state == f_x) num_pos = i;
1022
- if (isdigit (text_buffer[prev_pointer].line [i]) && (state == f_x || state == f_num))
1023
- state = f_num;
1024
- else switch (text_buffer[prev_pointer].line [i]) {
1025
- case ' ' :
1026
- if (state == begin || state == f_space)
1027
- state = f_space;
1028
- break ;
1029
- case ' (' :
1030
- if (state == begin || state == f_space)
1031
- state = f_lparen;
1032
- break ;
1033
- case ' x' :
1034
- if (state == f_lparen)
1035
- state = f_x;
1036
- break ;
1037
- case ' )' :
1038
- if (state == f_num)
1039
- state = f_rparen;
1040
- break ;
1041
- default :
1042
- if (i > last)
1043
- state = err;
1044
- break ;
1045
- }
1046
- if (state == f_rparen) break ;
1047
- }
1048
- if (state == begin || state == f_space || state == f_rparen) {
1049
- is_dup = true ;
1050
- last++;
1051
- }
1052
- if (is_dup) {
1053
- int lastCount = 1 ;
1054
- if (num_pos > 0 )
1055
- sscanf (text_buffer[prev_pointer].line + num_pos, " %d" , &lastCount);
1056
-
1057
- sprintf (text_buffer[prev_pointer].line + last, " (x%d)" , lastCount + 1 );
1058
- return ;
1013
+
1014
+ if (wrapped_str == text_buffer[prev_pointer].message ){
1015
+ text_buffer[prev_pointer].duplicate_count ++;
1016
+ std::string test_fit = wrapped_str + " (x" + std::to_string (text_buffer[prev_pointer].duplicate_count ) + " )" ;
1017
+ if (string_length (test_fit, buf_style) >= width){
1018
+ text_buffer[prev_pointer].line_count = line_count + 1 ;
1019
+ // The duplicate count in parenthesis is on its own line
1020
+ text_buffer[prev_pointer].duplicate_overflow = true ;
1059
1021
}
1022
+ }else {
1023
+ text_buffer[buf_pointer].message = wrapped_str;
1024
+ text_buffer[buf_pointer].line_count = line_count;
1025
+ text_buffer[buf_pointer].duplicate_count = 1 ;
1026
+ text_buffer[buf_pointer].duplicate_overflow = false ;
1027
+ if (buf_pointer == (TEXT_BUF_LEN - 1 ))
1028
+ buf_pointer = 0 ;
1029
+ else buf_pointer++;
1060
1030
}
1061
1031
1062
1032
text_sbar->setPosition (58 ); // TODO: This seems oddly specific
1063
- if (buf_pointer == mark_where_printing_long) {
1064
- printing_long = true ;
1065
- print_buf ();
1066
- through_sending ();
1067
- }
1068
- sprintf ((char *)text_buffer[buf_pointer].line , " %-49.49s" , str.c_str ());
1069
- if (buf_pointer == (TEXT_BUF_LEN - 1 ))
1070
- buf_pointer = 0 ;
1071
- else buf_pointer++;
1072
-
1073
1033
}
1074
1034
1075
1035
void add_caster_needs_to_buf (std::string needs_what, unsigned short pre_indent, unsigned short indent) {
@@ -1083,68 +1043,84 @@ void add_caster_needs_to_buf(std::string needs_what, unsigned short pre_indent,
1083
1043
}
1084
1044
1085
1045
void init_buf () {
1086
- for (short i = 0 ; i < TEXT_BUF_LEN; i++)
1087
- sprintf ((char *) text_buffer[buf_pointer].line , " " );
1046
+ for (short i = 0 ; i < TEXT_BUF_LEN; i++){
1047
+ // Buffer messages are no longer forced down to 50 chars each. In an effort to keep memory usage predictable,
1048
+ // I've set an expected capacity of 100 per message.
1049
+ text_buffer[i].message .reserve (100 );
1050
+ text_buffer[i].line_count = 1 ;
1051
+ text_buffer[i].duplicate_count = 1 ;
1052
+ text_buffer[i].duplicate_overflow = false ;
1053
+ }
1088
1054
}
1089
1055
1090
1056
void print_buf () {
1091
- short num_lines_printed = 0 ;
1092
- long ctrl_val;
1093
- short line_to_print;
1094
- long start_print_point;
1095
1057
rectangle store_text_rect,dest_rect,erase_rect = {2 ,2 ,136 ,255 };
1096
1058
1097
1059
text_area_gworld ().setActive (false );
1098
1060
clear_scale_aware_text (text_area_gworld ());
1099
1061
1100
1062
// First clean up gworld with pretty patterns
1101
1063
tileImage (text_area_gworld (), erase_rect,bg[6 ]);
1064
+
1065
+ // Don't draw wrapped scale-aware text outside of the viewport
1066
+ clip_rect (text_area_gworld (), erase_rect);
1067
+
1068
+ // Handling scrolling is a lot more confusing now.
1069
+ // Think of line 0 as the LAST line of the most recently printed message. We count up from that accounting for
1070
+ // multiple lines being stored in each message, to find the BOTTOM-MOST message to print first.
1071
+ long lines_clipped_below = 58 - text_sbar->getPosition ();
1072
+ int message_idx = buf_pointer - 1 ;
1073
+ if (message_idx < 0 )
1074
+ message_idx = TEXT_BUF_LEN + message_idx;
1075
+ int line = 0 ;
1076
+ while (line + text_buffer[message_idx].line_count <= lines_clipped_below){
1077
+ line += text_buffer[message_idx].line_count ;
1078
+ message_idx--;
1079
+ if (message_idx < 0 )
1080
+ message_idx = TEXT_BUF_LEN + message_idx;
1081
+ }
1102
1082
1103
- ctrl_val = 58 - text_sbar->getPosition ();
1104
- start_print_point = buf_pointer - LINES_IN_TEXT_WIN - ctrl_val;
1105
- if (start_print_point< 0 )
1106
- start_print_point= TEXT_BUF_LEN + start_print_point;
1107
- line_to_print= start_print_point;
1083
+ // Shift the text down this many lines, counting on clip_rect to hide the overflow:
1084
+ int line_offset = lines_clipped_below - line;
1085
+ int num_lines_total = 0 ;
1086
+ int num_lines_visible = -line_offset;
1108
1087
1109
1088
location moveTo;
1110
- while ((line_to_print!= buf_pointer) && (num_lines_printed < LINES_IN_TEXT_WIN)) {
1111
- moveTo = location (4 , 1 + 12 * num_lines_printed);
1112
- sf::Text text (text_buffer[line_to_print].line , *ResMgr::fonts.get (" plain" ), 12 * get_ui_scale ());
1113
- text.setColor (Colours::BLACK);
1114
- text.setPosition (moveTo);
1115
- draw_scale_aware_text (text_area_gworld (), text);
1116
- num_lines_printed++;
1117
- line_to_print++;
1118
- if (line_to_print== TEXT_BUF_LEN) {
1119
- line_to_print= 0 ;
1120
- }
1121
-
1122
- if ((num_lines_printed == LINES_IN_TEXT_WIN - 1 ) && (printing_long)) {
1123
- line_to_print= buf_pointer;
1089
+ while (num_lines_visible < LINES_IN_TEXT_WIN){
1090
+ std::string message = text_buffer[message_idx].message ;
1091
+ int indent = message.find_first_not_of (' ' );
1092
+ if (indent != std::string::npos){
1093
+ if (text_buffer[message_idx].duplicate_count > 1 ){
1094
+ if (text_buffer[message_idx].duplicate_overflow ){
1095
+ message += " \n " + std::string (indent, ' ' );
1096
+ }else {
1097
+ message += " " ;
1098
+ }
1099
+ message += " (x" + std::to_string (text_buffer[message_idx].duplicate_count ) + " )" ;
1100
+ }
1101
+
1102
+ moveTo = location (4 , 1 + 12 * (LINES_IN_TEXT_WIN + line_offset - num_lines_total - text_buffer[message_idx].line_count ));
1103
+ sf::Text text (message, *ResMgr::fonts.get (" plain" ), 12 * get_ui_scale ());
1104
+ text.setColor (Colours::BLACK);
1105
+ text.setPosition (moveTo);
1106
+ draw_scale_aware_text (text_area_gworld (), text);
1124
1107
}
1125
1108
1109
+ num_lines_visible += text_buffer[message_idx].line_count ;
1110
+ num_lines_total += text_buffer[message_idx].line_count ;
1111
+ message_idx--;
1112
+ if (message_idx < 0 )
1113
+ message_idx = TEXT_BUF_LEN + message_idx;
1126
1114
}
1127
1115
1128
1116
text_area_gworld ().setActive ();
1129
1117
text_area_gworld ().display ();
1130
1118
}
1131
1119
1132
- void restart_printing () {
1133
- lines_to_print = 0 ;
1134
- // clear_text_panel();
1135
- }
1136
-
1137
1120
void restore_mode () {
1138
1121
overall_mode = store_mode;
1139
1122
}
1140
1123
1141
- void through_sending () {
1142
- mark_where_printing_long = buf_pointer + LINES_IN_TEXT_WIN - 1 ;
1143
- if (mark_where_printing_long > TEXT_BUF_LEN - 1 )
1144
- mark_where_printing_long -= TEXT_BUF_LEN;
1145
- printing_long = false ;
1146
- }
1147
-
1148
1124
/* Draw a bitmap in the world window. hor in 0 .. 8, vert in 0 .. 8,
1149
1125
object is ptr. to bitmap to be drawn, and masking is for Copybits. */
1150
1126
void Draw_Some_Item (const sf::Texture& src_gworld, rectangle src_rect, sf::RenderTarget& targ_gworld,location target, char masked, short main_win) {
0 commit comments