@@ -51,6 +51,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51
51
#include " settings.h"
52
52
#include " client.h"
53
53
#include " util/string.h" // for parseColorString()
54
+ #include " fontengine.h"
54
55
55
56
#define MY_CHECKPOS (a,b ) \
56
57
if (v_pos.size() != 2 ) { \
@@ -68,6 +69,44 @@ with this program; if not, write to the Free Software Foundation, Inc.,
68
69
/*
69
70
GUIFormSpecMenu
70
71
*/
72
+ static unsigned int font_line_height (gui::IGUIFont *font)
73
+ {
74
+ return font->getDimension (L" Ay" ).Height + font->getKerningHeight ();
75
+ }
76
+
77
+ static gui::IGUIFont *select_font_by_line_height (double target_line_height)
78
+ {
79
+ // We don't get to directly select a font according to its
80
+ // baseline-to-baseline height. Rather, we select by em size.
81
+ // The ratio between these varies between fonts. The font
82
+ // engine also takes its size parameter not specified in pixels,
83
+ // as we want, but scaled by display density and gui_scaling,
84
+ // so invert that scaling here. Use a binary search among
85
+ // requested sizes to find the right font. Our starting bounds
86
+ // are an em height of 1 (being careful not to request size 0,
87
+ // which crashes the freetype system) and an em height of the
88
+ // target baseline-to-baseline height.
89
+ unsigned int loreq = ceil (1 / porting::getDisplayDensity ()
90
+ / g_settings->getFloat (" gui_scaling" ));
91
+ unsigned int hireq = ceil (target_line_height
92
+ / porting::getDisplayDensity ()
93
+ / g_settings->getFloat (" gui_scaling" ));
94
+ unsigned int lohgt = font_line_height (glb_fontengine->getFont (loreq));
95
+ unsigned int hihgt = font_line_height (glb_fontengine->getFont (hireq));
96
+ while (hireq - loreq > 1 && lohgt != hihgt) {
97
+ unsigned int nureq = (loreq + hireq) >> 1 ;
98
+ unsigned int nuhgt = font_line_height (glb_fontengine->getFont (nureq));
99
+ if (nuhgt < target_line_height) {
100
+ loreq = nureq;
101
+ lohgt = nuhgt;
102
+ } else {
103
+ hireq = nureq;
104
+ hihgt = nuhgt;
105
+ }
106
+ }
107
+ return glb_fontengine->getFont (target_line_height - lohgt < hihgt - target_line_height ? loreq : hireq);
108
+ }
109
+
71
110
GUIFormSpecMenu::GUIFormSpecMenu (irr::IrrlichtDevice* dev,
72
111
gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
73
112
InventoryManager *invmgr, IGameDef *gamedef,
@@ -89,7 +128,8 @@ GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev,
89
128
m_lock(false ),
90
129
m_form_src(fsrc),
91
130
m_text_dst(tdst),
92
- m_formspec_version(0 )
131
+ m_formspec_version(0 ),
132
+ m_font(NULL )
93
133
#ifdef __ANDROID__
94
134
,m_JavaDialogFieldName(L" " )
95
135
#endif
@@ -266,13 +306,11 @@ void GUIFormSpecMenu::parseSize(parserData* data,std::string element)
266
306
if (((parts.size () == 2 ) || parts.size () == 3 ) ||
267
307
((parts.size () > 3 ) && (m_formspec_version > FORMSPEC_API_VERSION)))
268
308
{
269
- v2f invsize;
270
-
271
309
if (parts[1 ].find (' ;' ) != std::string::npos)
272
310
parts[1 ] = parts[1 ].substr (0 ,parts[1 ].find (' ;' ));
273
311
274
- invsize.X = stof (parts[0 ]);
275
- invsize.Y = stof (parts[1 ]);
312
+ data-> invsize .X = MYMAX ( 0 , stof (parts[0 ]) );
313
+ data-> invsize .Y = MYMAX ( 0 , stof (parts[1 ]) );
276
314
277
315
lockSize (false );
278
316
if (parts.size () == 3 ) {
@@ -281,70 +319,7 @@ void GUIFormSpecMenu::parseSize(parserData* data,std::string element)
281
319
}
282
320
}
283
321
284
- double cur_scaling = porting::getDisplayDensity () *
285
- g_settings->getFloat (" gui_scaling" );
286
-
287
- if (m_lock) {
288
- v2u32 current_screensize = m_device->getVideoDriver ()->getScreenSize ();
289
- v2u32 delta = current_screensize - m_lockscreensize;
290
-
291
- if (current_screensize.Y > m_lockscreensize.Y )
292
- delta.Y /= 2 ;
293
- else
294
- delta.Y = 0 ;
295
-
296
- if (current_screensize.X > m_lockscreensize.X )
297
- delta.X /= 2 ;
298
- else
299
- delta.X = 0 ;
300
-
301
- offset = v2s32 (delta.X ,delta.Y );
302
-
303
- data->screensize = m_lockscreensize;
304
-
305
- // fixed scaling for fixed size gui elements */
306
- cur_scaling = LEGACY_SCALING;
307
- }
308
- else {
309
- offset = v2s32 (0 ,0 );
310
- }
311
-
312
- /* adjust image size to dpi */
313
- int y_partition = 15 ;
314
- imgsize = v2s32 (data->screensize .Y /y_partition, data->screensize .Y /y_partition);
315
- int min_imgsize = DEFAULT_IMGSIZE * cur_scaling;
316
- while ((min_imgsize > imgsize.Y ) && (y_partition > 1 )) {
317
- y_partition--;
318
- imgsize = v2s32 (data->screensize .Y /y_partition, data->screensize .Y /y_partition);
319
- }
320
- assert (y_partition > 0 );
321
-
322
- /* adjust spacing to dpi */
323
- spacing = v2s32 (imgsize.X +(DEFAULT_XSPACING * cur_scaling),
324
- imgsize.Y +(DEFAULT_YSPACING * cur_scaling));
325
-
326
- padding = v2s32 (data->screensize .Y /imgsize.Y , data->screensize .Y /imgsize.Y );
327
-
328
- /* adjust padding to dpi */
329
- padding = v2s32 (
330
- (padding.X /(2.0 /3.0 )) * cur_scaling,
331
- (padding.X /(2.0 /3.0 )) * cur_scaling
332
- );
333
- data->size = v2s32 (
334
- padding.X *2 +spacing.X *(invsize.X -1.0 )+imgsize.X ,
335
- padding.Y *2 +spacing.Y *(invsize.Y -1.0 )+imgsize.Y + m_btn_height - 5
336
- );
337
- data->rect = core::rect<s32>(
338
- data->screensize .X /2 - data->size .X /2 + offset.X ,
339
- data->screensize .Y /2 - data->size .Y /2 + offset.Y ,
340
- data->screensize .X /2 + data->size .X /2 + offset.X ,
341
- data->screensize .Y /2 + data->size .Y /2 + offset.Y
342
- );
343
-
344
- DesiredRect = data->rect ;
345
- recalculateAbsolutePosition (false );
346
- data->basepos = getBasePos ();
347
- data->bp_set = 2 ;
322
+ data->explicit_size = true ;
348
323
return ;
349
324
}
350
325
errorstream<< " Invalid size element (" << parts.size () << " ): '" << element << " '" << std::endl;
@@ -397,7 +372,7 @@ void GUIFormSpecMenu::parseList(parserData* data,std::string element)
397
372
return ;
398
373
}
399
374
400
- if (data->bp_set != 2 )
375
+ if (! data->explicit_size )
401
376
errorstream<<" WARNING: invalid use of list without a size[] element" <<std::endl;
402
377
m_inventorylists.push_back (ListDrawSpec (loc, listname, pos, geom, start_i));
403
378
return ;
@@ -433,14 +408,9 @@ void GUIFormSpecMenu::parseCheckbox(parserData* data,std::string element)
433
408
434
409
std::wstring wlabel = narrow_to_wide (label.c_str ());
435
410
436
- gui::IGUIFont *font = NULL ;
437
- gui::IGUISkin* skin = Environment->getSkin ();
438
- if (skin)
439
- font = skin->getFont ();
440
-
441
411
core::rect<s32> rect = core::rect<s32>(
442
412
pos.X , pos.Y + ((imgsize.Y /2 ) - m_btn_height),
443
- pos.X + font ->getDimension (wlabel.c_str ()).Width + 25 , // text size + size of checkbox
413
+ pos.X + m_font ->getDimension (wlabel.c_str ()).Width + 25 , // text size + size of checkbox
444
414
pos.Y + ((imgsize.Y /2 ) + m_btn_height));
445
415
446
416
FieldSpec spec (
@@ -518,35 +488,6 @@ void GUIFormSpecMenu::parseScrollBar(parserData* data, std::string element)
518
488
e->setSmallStep (10 );
519
489
e->setLargeStep (100 );
520
490
521
- if (!m_lock) {
522
- core::rect<s32> relative_rect = e->getRelativePosition ();
523
-
524
- if (!is_horizontal) {
525
- s32 original_width = relative_rect.getWidth ();
526
- s32 width = (original_width/(2.0 /3.0 ))
527
- * porting::getDisplayDensity ()
528
- * g_settings->getFloat (" gui_scaling" );
529
- e->setRelativePosition (core::rect<s32>(
530
- relative_rect.UpperLeftCorner .X ,
531
- relative_rect.UpperLeftCorner .Y ,
532
- relative_rect.LowerRightCorner .X + (width - original_width),
533
- relative_rect.LowerRightCorner .Y
534
- ));
535
- }
536
- else {
537
- s32 original_height = relative_rect.getHeight ();
538
- s32 height = (original_height/(2.0 /3.0 ))
539
- * porting::getDisplayDensity ()
540
- * g_settings->getFloat (" gui_scaling" );
541
- e->setRelativePosition (core::rect<s32>(
542
- relative_rect.UpperLeftCorner .X ,
543
- relative_rect.UpperLeftCorner .Y ,
544
- relative_rect.LowerRightCorner .X ,
545
- relative_rect.LowerRightCorner .Y + (height - original_height)
546
- ));
547
- }
548
- }
549
-
550
491
m_scrollbars.push_back (std::pair<FieldSpec,gui::IGUIScrollBar*>(spec,e));
551
492
m_fields.push_back (spec);
552
493
return ;
@@ -576,7 +517,7 @@ void GUIFormSpecMenu::parseImage(parserData* data,std::string element)
576
517
geom.X = stof (v_geom[0 ]) * (float )imgsize.X ;
577
518
geom.Y = stof (v_geom[1 ]) * (float )imgsize.Y ;
578
519
579
- if (data->bp_set != 2 )
520
+ if (! data->explicit_size )
580
521
errorstream<<" WARNING: invalid use of image without a size[] element" <<std::endl;
581
522
m_images.push_back (ImageDrawSpec (name, pos, geom));
582
523
return ;
@@ -592,7 +533,7 @@ void GUIFormSpecMenu::parseImage(parserData* data,std::string element)
592
533
pos.X += stof (v_pos[0 ]) * (float ) spacing.X ;
593
534
pos.Y += stof (v_pos[1 ]) * (float ) spacing.Y ;
594
535
595
- if (data->bp_set != 2 )
536
+ if (! data->explicit_size )
596
537
errorstream<<" WARNING: invalid use of image without a size[] element" <<std::endl;
597
538
m_images.push_back (ImageDrawSpec (name, pos));
598
539
return ;
@@ -622,7 +563,7 @@ void GUIFormSpecMenu::parseItemImage(parserData* data,std::string element)
622
563
geom.X = stof (v_geom[0 ]) * (float )imgsize.X ;
623
564
geom.Y = stof (v_geom[1 ]) * (float )imgsize.Y ;
624
565
625
- if (data->bp_set != 2 )
566
+ if (! data->explicit_size )
626
567
errorstream<<" WARNING: invalid use of item_image without a size[] element" <<std::endl;
627
568
m_itemimages.push_back (ImageDrawSpec (name, pos, geom));
628
569
return ;
@@ -658,7 +599,7 @@ void GUIFormSpecMenu::parseButton(parserData* data,std::string element,
658
599
core::rect<s32>(pos.X , pos.Y - m_btn_height,
659
600
pos.X + geom.X , pos.Y + m_btn_height);
660
601
661
- if (data->bp_set != 2 )
602
+ if (! data->explicit_size )
662
603
errorstream<<" WARNING: invalid use of button without a size[] element" <<std::endl;
663
604
664
605
label = unescape_string (label);
@@ -717,7 +658,7 @@ void GUIFormSpecMenu::parseBackground(parserData* data,std::string element)
717
658
}
718
659
}
719
660
720
- if (data->bp_set != 2 )
661
+ if (! data->explicit_size )
721
662
errorstream<<" WARNING: invalid use of background without a size[] element" <<std::endl;
722
663
m_backgrounds.push_back (ImageDrawSpec (name, pos, geom));
723
664
return ;
@@ -1008,8 +949,9 @@ void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element)
1008
949
1009
950
if (label.length () >= 1 )
1010
951
{
1011
- rect.UpperLeftCorner .Y -= m_btn_height;
1012
- rect.LowerRightCorner .Y = rect.UpperLeftCorner .Y + m_btn_height;
952
+ int font_height = font_line_height (m_font);
953
+ rect.UpperLeftCorner .Y -= font_height;
954
+ rect.LowerRightCorner .Y = rect.UpperLeftCorner .Y + font_height;
1013
955
Environment->addStaticText (spec.flabel .c_str (), rect, false , true , this , 0 );
1014
956
}
1015
957
@@ -1038,20 +980,7 @@ void GUIFormSpecMenu::parseSimpleField(parserData* data,
1038
980
1039
981
core::rect<s32> rect;
1040
982
1041
- if (!data->bp_set )
1042
- {
1043
- rect = core::rect<s32>(
1044
- data->screensize .X /2 - 580 /2 ,
1045
- data->screensize .Y /2 - 300 /2 ,
1046
- data->screensize .X /2 + 580 /2 ,
1047
- data->screensize .Y /2 + 300 /2
1048
- );
1049
- DesiredRect = rect;
1050
- recalculateAbsolutePosition (false );
1051
- data->basepos = getBasePos ();
1052
- data->bp_set = 1 ;
1053
- }
1054
- else if (data->bp_set == 2 )
983
+ if (data->explicit_size )
1055
984
errorstream<<" WARNING: invalid use of unpositioned \" field\" in inventory" <<std::endl;
1056
985
1057
986
v2s32 pos = padding + AbsoluteRect.UpperLeftCorner ;
@@ -1103,8 +1032,9 @@ void GUIFormSpecMenu::parseSimpleField(parserData* data,
1103
1032
1104
1033
if (label.length () >= 1 )
1105
1034
{
1106
- rect.UpperLeftCorner .Y -= m_btn_height;
1107
- rect.LowerRightCorner .Y = rect.UpperLeftCorner .Y + m_btn_height;
1035
+ int font_height = font_line_height (m_font);
1036
+ rect.UpperLeftCorner .Y -= font_height;
1037
+ rect.LowerRightCorner .Y = rect.UpperLeftCorner .Y + font_height;
1108
1038
Environment->addStaticText (spec.flabel .c_str (), rect, false , true , this , 0 );
1109
1039
}
1110
1040
}
@@ -1147,7 +1077,7 @@ void GUIFormSpecMenu::parseTextArea(parserData* data,
1147
1077
1148
1078
core::rect<s32> rect = core::rect<s32>(pos.X , pos.Y , pos.X +geom.X , pos.Y +geom.Y );
1149
1079
1150
- if (data->bp_set != 2 )
1080
+ if (! data->explicit_size )
1151
1081
errorstream<<" WARNING: invalid use of positioned " <<type<<" without a size[] element" <<std::endl;
1152
1082
1153
1083
if (m_form_src)
@@ -1199,8 +1129,9 @@ void GUIFormSpecMenu::parseTextArea(parserData* data,
1199
1129
1200
1130
if (label.length () >= 1 )
1201
1131
{
1202
- rect.UpperLeftCorner .Y -= m_btn_height;
1203
- rect.LowerRightCorner .Y = rect.UpperLeftCorner .Y + m_btn_height;
1132
+ int font_height = font_line_height (m_font);
1133
+ rect.UpperLeftCorner .Y -= font_height;
1134
+ rect.LowerRightCorner .Y = rect.UpperLeftCorner .Y + font_height;
1204
1135
Environment->addStaticText (spec.flabel .c_str (), rect, false , true , this , 0 );
1205
1136
}
1206
1137
}
@@ -1240,33 +1171,46 @@ void GUIFormSpecMenu::parseLabel(parserData* data,std::string element)
1240
1171
1241
1172
v2s32 pos = padding;
1242
1173
pos.X += stof (v_pos[0 ]) * (float )spacing.X ;
1243
- pos.Y += stof (v_pos[1 ]) * (float )spacing.Y ;
1174
+ pos.Y += ( stof (v_pos[1 ]) + 7.0 / 30.0 ) * (float )spacing.Y ;
1244
1175
1245
- if (data->bp_set != 2 )
1176
+ if (! data->explicit_size )
1246
1177
errorstream<<" WARNING: invalid use of label without a size[] element" <<std::endl;
1247
1178
1248
- text = unescape_string (text);
1249
-
1250
- std::wstring wlabel = narrow_to_wide (text.c_str ());
1251
-
1252
- gui::IGUIFont *font = NULL ;
1253
- gui::IGUISkin* skin = Environment->getSkin ();
1254
- if (skin)
1255
- font = skin->getFont ();
1179
+ int font_height = font_line_height (m_font);
1256
1180
1257
- core::rect<s32> rect = core::rect<s32>(
1258
- pos.X , pos.Y +((imgsize.Y /2 ) - m_btn_height),
1259
- pos.X + font->getDimension (wlabel.c_str ()).Width ,
1260
- pos.Y +((imgsize.Y /2 ) + m_btn_height));
1181
+ text = unescape_string (text);
1182
+ std::vector<std::string> lines = split (text, ' \n ' );
1183
+
1184
+ for (unsigned int i = 0 ; i != lines.size (); i++) {
1185
+ // Lines are spaced at the nominal distance of
1186
+ // 2/5 inventory slot, even if the font doesn't
1187
+ // quite match that. This provides consistent
1188
+ // form layout, at the expense of sometimes
1189
+ // having sub-optimal spacing for the font.
1190
+ // We multiply by 2 and then divide by 5, rather
1191
+ // than multiply by 0.4, to get exact results
1192
+ // in the integer cases: 0.4 is not exactly
1193
+ // representable in binary floating point.
1194
+ s32 posy = pos.Y + ((float )i) * spacing.Y * 2.0 / 5.0 ;
1195
+ std::wstring wlabel = narrow_to_wide (lines[i].c_str ());
1196
+ core::rect<s32> rect = core::rect<s32>(
1197
+ pos.X , posy - font_height,
1198
+ pos.X + m_font->getDimension (wlabel.c_str ()).Width ,
1199
+ posy + font_height);
1200
+ FieldSpec spec (
1201
+ L" " ,
1202
+ wlabel,
1203
+ L" " ,
1204
+ 258 +m_fields.size ()
1205
+ );
1206
+ gui::IGUIStaticText *e =
1207
+ Environment->addStaticText (spec.flabel .c_str (),
1208
+ rect, false , false , this , spec.fid );
1209
+ e->setTextAlignment (gui::EGUIA_UPPERLEFT,
1210
+ gui::EGUIA_CENTER);
1211
+ m_fields.push_back (spec);
1212
+ }
1261
1213
1262
- FieldSpec spec (
1263
- L" " ,
1264
- wlabel,
1265
- L" " ,
1266
- 258 +m_fields.size ()
1267
- );
1268
- Environment->addStaticText (spec.flabel .c_str (), rect, false , false , this , spec.fid );
1269
- m_fields.push_back (spec);
1270
1214
return ;
1271
1215
}
1272
1216
errorstream<< " Invalid label element(" << parts.size () << " ): '" << element << " '" << std::endl;
@@ -1288,21 +1232,15 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element)
1288
1232
pos.X += stof (v_pos[0 ]) * (float )spacing.X ;
1289
1233
pos.Y += stof (v_pos[1 ]) * (float )spacing.Y ;
1290
1234
1291
- gui::IGUIFont *font = NULL ;
1292
- gui::IGUISkin* skin = Environment->getSkin ();
1293
- if (skin)
1294
- font = skin->getFont ();
1295
-
1296
1235
core::rect<s32> rect = core::rect<s32>(
1297
1236
pos.X , pos.Y +((imgsize.Y /2 )- m_btn_height),
1298
1237
pos.X +15 , pos.Y +
1299
- (font->getKerningHeight () +
1300
- font->getDimension (text.c_str ()).Height )
1238
+ font_line_height (m_font)
1301
1239
* (text.length ()+1 )
1302
1240
+((imgsize.Y /2 )- m_btn_height));
1303
1241
// actually text.length() would be correct but adding +1 avoids to break all mods
1304
1242
1305
- if (data->bp_set != 2 )
1243
+ if (! data->explicit_size )
1306
1244
errorstream<<" WARNING: invalid use of label without a size[] element" <<std::endl;
1307
1245
1308
1246
std::wstring label = L" " ;
@@ -1368,7 +1306,7 @@ void GUIFormSpecMenu::parseImageButton(parserData* data,std::string element,
1368
1306
1369
1307
core::rect<s32> rect = core::rect<s32>(pos.X , pos.Y , pos.X +geom.X , pos.Y +geom.Y );
1370
1308
1371
- if (data->bp_set != 2 )
1309
+ if (! data->explicit_size )
1372
1310
errorstream<<" WARNING: invalid use of image_button without a size[] element" <<std::endl;
1373
1311
1374
1312
image_name = unescape_string (image_name);
@@ -1452,7 +1390,7 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data,std::string element)
1452
1390
pos.X += stof (v_pos[0 ]) * (float )spacing.X ;
1453
1391
pos.Y += stof (v_pos[1 ]) * (float )spacing.Y - m_btn_height * 2 ;
1454
1392
v2s32 geom;
1455
- geom.X = data-> screensize . Y ;
1393
+ geom.X = DesiredRect. getWidth () ;
1456
1394
geom.Y = m_btn_height*2 ;
1457
1395
1458
1396
core::rect<s32> rect = core::rect<s32>(pos.X , pos.Y , pos.X +geom.X ,
@@ -1519,7 +1457,7 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element)
1519
1457
1520
1458
core::rect<s32> rect = core::rect<s32>(pos.X , pos.Y , pos.X +geom.X , pos.Y +geom.Y );
1521
1459
1522
- if (data->bp_set != 2 )
1460
+ if (! data->explicit_size )
1523
1461
errorstream<<" WARNING: invalid use of item_image_button without a size[] element" <<std::endl;
1524
1462
1525
1463
IItemDefManager *idef = m_gamedef->idef ();
@@ -1683,6 +1621,30 @@ bool GUIFormSpecMenu::parseVersionDirect(std::string data)
1683
1621
return false ;
1684
1622
}
1685
1623
1624
+ bool GUIFormSpecMenu::parseSizeDirect (parserData* data, std::string element)
1625
+ {
1626
+ if (element == " " )
1627
+ return false ;
1628
+
1629
+ std::vector<std::string> parts = split (element,' [' );
1630
+
1631
+ if (parts.size () < 2 )
1632
+ return false ;
1633
+
1634
+ std::string type = trim (parts[0 ]);
1635
+ std::string description = trim (parts[1 ]);
1636
+
1637
+ if (type != " size" && type != " invsize" )
1638
+ return false ;
1639
+
1640
+ if (type == " invsize" )
1641
+ log_deprecated (" Deprecated formspec element \" invsize\" is used" );
1642
+
1643
+ parseSize (data, description);
1644
+
1645
+ return true ;
1646
+ }
1647
+
1686
1648
void GUIFormSpecMenu::parseElement (parserData* data, std::string element)
1687
1649
{
1688
1650
// some prechecks
@@ -1708,17 +1670,6 @@ void GUIFormSpecMenu::parseElement(parserData* data, std::string element)
1708
1670
std::string type = trim (parts[0 ]);
1709
1671
std::string description = trim (parts[1 ]);
1710
1672
1711
- if (type == " size" ) {
1712
- parseSize (data,description);
1713
- return ;
1714
- }
1715
-
1716
- if (type == " invsize" ) {
1717
- log_deprecated (" Deprecated formspec element \" invsize\" is used" );
1718
- parseSize (data,description);
1719
- return ;
1720
- }
1721
-
1722
1673
if (type == " list" ) {
1723
1674
parseList (data,description);
1724
1675
return ;
@@ -1849,14 +1800,6 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
1849
1800
return ;
1850
1801
}
1851
1802
1852
- gui::IGUIFont *font = NULL ;
1853
- gui::IGUISkin* skin = Environment->getSkin ();
1854
- if (skin)
1855
- font = skin->getFont ();
1856
-
1857
- m_btn_height = font->getDimension (L" Some unimportant test String" ).Height ;
1858
- assert (m_btn_height > 0 );
1859
-
1860
1803
parserData mydata;
1861
1804
1862
1805
// preserve tables
@@ -1895,12 +1838,6 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
1895
1838
// Base position of contents of form
1896
1839
mydata.basepos = getBasePos ();
1897
1840
1898
- // State of basepos, 0 = not set, 1= set by formspec, 2 = set by size[] element
1899
- // Used to adjust form size automatically if needed
1900
- // A proceed button is added if there is no size[] element
1901
- mydata.bp_set = 0 ;
1902
-
1903
-
1904
1841
/* Convert m_init_draw_spec to m_inventorylists */
1905
1842
1906
1843
m_inventorylists.clear ();
@@ -1954,13 +1891,132 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
1954
1891
}
1955
1892
}
1956
1893
1894
+ /* we need size first in order to calculate image scale */
1895
+ mydata.explicit_size = false ;
1896
+ for (; i< elements.size (); i++) {
1897
+ if (!parseSizeDirect (&mydata, elements[i])) {
1898
+ break ;
1899
+ }
1900
+ }
1901
+
1902
+ if (mydata.explicit_size ) {
1903
+ // compute scaling for specified form size
1904
+ if (m_lock) {
1905
+ v2u32 current_screensize = m_device->getVideoDriver ()->getScreenSize ();
1906
+ v2u32 delta = current_screensize - m_lockscreensize;
1907
+
1908
+ if (current_screensize.Y > m_lockscreensize.Y )
1909
+ delta.Y /= 2 ;
1910
+ else
1911
+ delta.Y = 0 ;
1912
+
1913
+ if (current_screensize.X > m_lockscreensize.X )
1914
+ delta.X /= 2 ;
1915
+ else
1916
+ delta.X = 0 ;
1917
+
1918
+ offset = v2s32 (delta.X ,delta.Y );
1919
+
1920
+ mydata.screensize = m_lockscreensize;
1921
+ } else {
1922
+ offset = v2s32 (0 ,0 );
1923
+ }
1924
+
1925
+ double gui_scaling = g_settings->getFloat (" gui_scaling" );
1926
+ double screen_dpi = porting::getDisplayDensity () * 96 ;
1927
+
1928
+ double use_imgsize;
1929
+ if (m_lock) {
1930
+ // In fixed-size mode, inventory image size
1931
+ // is 0.53 inch multiplied by the gui_scaling
1932
+ // config parameter. This magic size is chosen
1933
+ // to make the main menu (15.5 inventory images
1934
+ // wide, including border) just fit into the
1935
+ // default window (800 pixels wide) at 96 DPI
1936
+ // and default scaling (1.00).
1937
+ use_imgsize = 0.53 * screen_dpi * gui_scaling;
1938
+ } else {
1939
+ // In variable-size mode, we prefer to make the
1940
+ // inventory image size 1/15 of screen height,
1941
+ // multiplied by the gui_scaling config parameter.
1942
+ // If the preferred size won't fit the whole
1943
+ // form on the screen, either horizontally or
1944
+ // vertically, then we scale it down to fit.
1945
+ // (The magic numbers in the computation of what
1946
+ // fits arise from the scaling factors in the
1947
+ // following stanza, including the form border,
1948
+ // help text space, and 0.1 inventory slot spare.)
1949
+ // However, a minimum size is also set, that
1950
+ // the image size can't be less than 0.3 inch
1951
+ // multiplied by gui_scaling, even if this means
1952
+ // the form doesn't fit the screen.
1953
+ double prefer_imgsize = mydata.screensize .Y / 15 *
1954
+ gui_scaling;
1955
+ double fitx_imgsize = mydata.screensize .X /
1956
+ ((5.0 /4.0 ) * (0.5 + mydata.invsize .X ));
1957
+ double fity_imgsize = mydata.screensize .Y /
1958
+ ((15.0 /13.0 ) * (0.85 * mydata.invsize .Y ));
1959
+ double screen_dpi = porting::getDisplayDensity () * 96 ;
1960
+ double min_imgsize = 0.3 * screen_dpi * gui_scaling;
1961
+ use_imgsize = MYMAX (min_imgsize, MYMIN (prefer_imgsize,
1962
+ MYMIN (fitx_imgsize, fity_imgsize)));
1963
+ }
1964
+
1965
+ // Everything else is scaled in proportion to the
1966
+ // inventory image size. The inventory slot spacing
1967
+ // is 5/4 image size horizontally and 15/13 image size
1968
+ // vertically. The padding around the form (incorporating
1969
+ // the border of the outer inventory slots) is 3/8
1970
+ // image size. Font height (baseline to baseline)
1971
+ // is 2/5 vertical inventory slot spacing, and button
1972
+ // half-height is 7/8 of font height.
1973
+ imgsize = v2s32 (use_imgsize, use_imgsize);
1974
+ spacing = v2s32 (use_imgsize*5.0 /4 , use_imgsize*15.0 /13 );
1975
+ padding = v2s32 (use_imgsize*3.0 /8 , use_imgsize*3.0 /8 );
1976
+ double target_font_height = use_imgsize*15.0 /13 * 0.4 ;
1977
+ m_btn_height = use_imgsize*15.0 /13 * 0.35 ;
1978
+
1979
+ m_font = select_font_by_line_height (target_font_height);
1980
+
1981
+ mydata.size = v2s32 (
1982
+ padding.X *2 +spacing.X *(mydata.invsize .X -1.0 )+imgsize.X ,
1983
+ padding.Y *2 +spacing.Y *(mydata.invsize .Y -1.0 )+imgsize.Y + m_btn_height*2.0 /3.0
1984
+ );
1985
+ DesiredRect = mydata.rect = core::rect<s32>(
1986
+ mydata.screensize .X /2 - mydata.size .X /2 + offset.X ,
1987
+ mydata.screensize .Y /2 - mydata.size .Y /2 + offset.Y ,
1988
+ mydata.screensize .X /2 + mydata.size .X /2 + offset.X ,
1989
+ mydata.screensize .Y /2 + mydata.size .Y /2 + offset.Y
1990
+ );
1991
+ } else {
1992
+ // Non-size[] form must consist only of text fields and
1993
+ // implicit "Proceed" button. Use default font, and
1994
+ // temporary form size which will be recalculated below.
1995
+ m_font = glb_fontengine->getFont ();
1996
+ m_btn_height = font_line_height (m_font) * 0.875 ;
1997
+ DesiredRect = core::rect<s32>(
1998
+ mydata.screensize .X /2 - 580 /2 ,
1999
+ mydata.screensize .Y /2 - 300 /2 ,
2000
+ mydata.screensize .X /2 + 580 /2 ,
2001
+ mydata.screensize .Y /2 + 300 /2
2002
+ );
2003
+ }
2004
+ recalculateAbsolutePosition (false );
2005
+ mydata.basepos = getBasePos ();
2006
+ m_tooltip_element->setOverrideFont (m_font);
2007
+
2008
+ gui::IGUISkin* skin = Environment->getSkin ();
2009
+ assert (skin != NULL );
2010
+ gui::IGUIFont *old_font = skin->getFont ();
2011
+ skin->setFont (m_font);
2012
+
1957
2013
for (; i< elements.size (); i++) {
1958
2014
parseElement (&mydata, elements[i]);
1959
2015
}
1960
2016
1961
- // If there's fields, add a Proceed button
1962
- if (m_fields. size () && mydata. bp_set != 2 ) {
1963
- // if the size wasn't set by an invsize[] or size[] adjust it now to fit all the fields
2017
+ // If there are fields without explicit size[] , add a " Proceed"
2018
+ // button and adjust size to fit all the fields.
2019
+ if (m_fields. size () && !mydata. explicit_size ) {
1964
2020
mydata.rect = core::rect<s32>(
1965
2021
mydata.screensize .X /2 - 580 /2 ,
1966
2022
mydata.screensize .Y /2 - 300 /2 ,
@@ -1992,6 +2048,8 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
1992
2048
|| !isMyChild (focused_element)
1993
2049
|| focused_element->getType () == gui::EGUIET_TAB_CONTROL)
1994
2050
setInitialFocus ();
2051
+
2052
+ skin->setFont (old_font);
1995
2053
}
1996
2054
1997
2055
#ifdef __ANDROID__
@@ -2068,11 +2126,6 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
2068
2126
{
2069
2127
video::IVideoDriver* driver = Environment->getVideoDriver ();
2070
2128
2071
- gui::IGUIFont *font = NULL ;
2072
- gui::IGUISkin* skin = Environment->getSkin ();
2073
- if (skin)
2074
- font = skin->getFont ();
2075
-
2076
2129
Inventory *inv = m_invmgr->getInventory (s.inventoryloc );
2077
2130
if (!inv){
2078
2131
infostream<<" GUIFormSpecMenu::drawList(): WARNING: "
@@ -2149,7 +2202,7 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
2149
2202
}
2150
2203
if (!item.empty ())
2151
2204
{
2152
- drawItemStack (driver, font , item,
2205
+ drawItemStack (driver, m_font , item,
2153
2206
rect, &AbsoluteClippingRect, m_gamedef);
2154
2207
}
2155
2208
@@ -2183,12 +2236,6 @@ void GUIFormSpecMenu::drawSelectedItem()
2183
2236
2184
2237
video::IVideoDriver* driver = Environment->getVideoDriver ();
2185
2238
2186
- // Get font
2187
- gui::IGUIFont *font = NULL ;
2188
- gui::IGUISkin* skin = Environment->getSkin ();
2189
- if (skin)
2190
- font = skin->getFont ();
2191
-
2192
2239
Inventory *inv = m_invmgr->getInventory (m_selected_item->inventoryloc );
2193
2240
assert (inv);
2194
2241
InventoryList *list = inv->getList (m_selected_item->listname );
@@ -2198,7 +2245,7 @@ void GUIFormSpecMenu::drawSelectedItem()
2198
2245
2199
2246
core::rect<s32> imgrect (0 ,0 ,imgsize.X ,imgsize.Y );
2200
2247
core::rect<s32> rect = imgrect + (m_pointer - imgrect.getCenter ());
2201
- drawItemStack (driver, font , stack, rect, NULL , m_gamedef);
2248
+ drawItemStack (driver, m_font , stack, rect, NULL , m_gamedef);
2202
2249
}
2203
2250
2204
2251
void GUIFormSpecMenu::drawMenu ()
@@ -2211,6 +2258,11 @@ void GUIFormSpecMenu::drawMenu()
2211
2258
}
2212
2259
}
2213
2260
2261
+ gui::IGUISkin* skin = Environment->getSkin ();
2262
+ assert (skin != NULL );
2263
+ gui::IGUIFont *old_font = skin->getFont ();
2264
+ skin->setFont (m_font);
2265
+
2214
2266
updateSelectedItem ();
2215
2267
2216
2268
video::IVideoDriver* driver = Environment->getVideoDriver ();
@@ -2409,6 +2461,8 @@ void GUIFormSpecMenu::drawMenu()
2409
2461
Draw dragged item stack
2410
2462
*/
2411
2463
drawSelectedItem ();
2464
+
2465
+ skin->setFont (old_font);
2412
2466
}
2413
2467
2414
2468
void GUIFormSpecMenu::updateSelectedItem ()
@@ -2665,6 +2719,30 @@ static bool isChild(gui::IGUIElement * tocheck, gui::IGUIElement * parent)
2665
2719
2666
2720
bool GUIFormSpecMenu::preprocessEvent (const SEvent& event)
2667
2721
{
2722
+ // The IGUITabControl renders visually using the skin's selected
2723
+ // font, which we override for the duration of form drawing,
2724
+ // but computes tab hotspots based on how it would have rendered
2725
+ // using the font that is selected at the time of button release.
2726
+ // To make these two consistent, temporarily override the skin's
2727
+ // font while the IGUITabControl is processing the event.
2728
+ if (event.EventType == EET_MOUSE_INPUT_EVENT &&
2729
+ event.MouseInput .Event == EMIE_LMOUSE_LEFT_UP) {
2730
+ s32 x = event.MouseInput .X ;
2731
+ s32 y = event.MouseInput .Y ;
2732
+ gui::IGUIElement *hovered =
2733
+ Environment->getRootGUIElement ()->getElementFromPoint (
2734
+ core::position2d<s32>(x, y));
2735
+ if (hovered->getType () == gui::EGUIET_TAB_CONTROL) {
2736
+ gui::IGUISkin* skin = Environment->getSkin ();
2737
+ assert (skin != NULL );
2738
+ gui::IGUIFont *old_font = skin->getFont ();
2739
+ skin->setFont (m_font);
2740
+ bool retval = hovered->OnEvent (event);
2741
+ skin->setFont (old_font);
2742
+ return retval;
2743
+ }
2744
+ }
2745
+
2668
2746
// Fix Esc/Return key being eaten by checkboxen and tables
2669
2747
if (event.EventType ==EET_KEY_INPUT_EVENT) {
2670
2748
KeyPress kp (event.KeyInput );
0 commit comments