@@ -604,7 +604,7 @@ void GUIFormSpecMenu::parseButton(parserData* data,std::string element,std::stri
604
604
void GUIFormSpecMenu::parseBackground (parserData* data,std::string element) {
605
605
std::vector<std::string> parts = split (element,' ;' );
606
606
607
- if (parts.size () == 3 ) {
607
+ if (( parts.size () == 3 ) || (parts. size () == 4 ) ) {
608
608
std::vector<std::string> v_pos = split (parts[0 ],' ,' );
609
609
std::vector<std::string> v_geom = split (parts[1 ],' ,' );
610
610
std::string name = unescape_string (parts[2 ]);
@@ -620,6 +620,14 @@ void GUIFormSpecMenu::parseBackground(parserData* data,std::string element) {
620
620
geom.X = stof (v_geom[0 ]) * (float )spacing.X ;
621
621
geom.Y = stof (v_geom[1 ]) * (float )spacing.Y ;
622
622
623
+ if (parts.size () == 4 ) {
624
+ m_clipbackground = is_yes (parts[3 ]);
625
+ if (m_clipbackground) {
626
+ pos.X = stoi (v_pos[0 ]); // acts as offset
627
+ pos.Y = stoi (v_pos[1 ]); // acts as offset
628
+ }
629
+ }
630
+
623
631
if (data->bp_set != 2 )
624
632
errorstream<<" WARNING: invalid use of background without a size[] element" <<std::endl;
625
633
m_backgrounds.push_back (ImageDrawSpec (name, pos, geom));
@@ -686,16 +694,16 @@ void GUIFormSpecMenu::parseTextList(parserData* data,std::string element) {
686
694
e->addItem (narrow_to_wide (unescape_string (items[i])).c_str () +1 );
687
695
}
688
696
else {
689
- std::string color = items[i].substr (1 , 6 );
697
+ std::string color = items[i].substr (0 , 7 );
690
698
std::wstring toadd =
691
699
narrow_to_wide (unescape_string (items[i]).c_str () + 7 );
692
700
693
701
e->addItem (toadd.c_str ());
694
702
695
- irr:: video::SColor toset ;
703
+ video::SColor tmp_color ;
696
704
697
- if (parseColor (color, toset ))
698
- e->setItemOverrideColor (i,toset );
705
+ if (parseColor (color, tmp_color, false ))
706
+ e->setItemOverrideColor (i,tmp_color );
699
707
}
700
708
}
701
709
else {
@@ -1329,7 +1337,6 @@ void GUIFormSpecMenu::parseBox(parserData* data,std::string element) {
1329
1337
if (parts.size () == 3 ) {
1330
1338
std::vector<std::string> v_pos = split (parts[0 ],' ,' );
1331
1339
std::vector<std::string> v_geom = split (parts[1 ],' ,' );
1332
- std::string color_str = parts[2 ];
1333
1340
1334
1341
MY_CHECKPOS (" box" ,0 );
1335
1342
MY_CHECKGEOM (" box" ,1 );
@@ -1342,10 +1349,10 @@ void GUIFormSpecMenu::parseBox(parserData* data,std::string element) {
1342
1349
geom.X = stof (v_geom[0 ]) * (float )spacing.X ;
1343
1350
geom.Y = stof (v_geom[1 ]) * (float )spacing.Y ;
1344
1351
1345
- irr:: video::SColor color ;
1352
+ video::SColor tmp_color ;
1346
1353
1347
- if (parseColor (color_str, color )) {
1348
- BoxDrawSpec spec (pos,geom,color );
1354
+ if (parseColor (parts[ 2 ], tmp_color, false )) {
1355
+ BoxDrawSpec spec (pos, geom, tmp_color );
1349
1356
1350
1357
m_boxes.push_back (spec);
1351
1358
}
@@ -1357,6 +1364,46 @@ void GUIFormSpecMenu::parseBox(parserData* data,std::string element) {
1357
1364
errorstream<< " Invalid Box element(" << parts.size () << " ): '" << element << " '" << std::endl;
1358
1365
}
1359
1366
1367
+ void GUIFormSpecMenu::parseBackgroundColor (parserData* data,std::string element) {
1368
+ std::vector<std::string> parts = split (element,' ;' );
1369
+
1370
+ if ((parts.size () == 1 ) || (parts.size () == 2 )) {
1371
+ parseColor (parts[0 ],m_bgcolor,false );
1372
+
1373
+ if (parts.size () == 2 ) {
1374
+ std::string fullscreen = parts[1 ];
1375
+ m_bgfullscreen = is_yes (fullscreen);
1376
+ }
1377
+ return ;
1378
+ }
1379
+ errorstream<< " Invalid bgcolor element(" << parts.size () << " ): '" << element << " '" << std::endl;
1380
+ }
1381
+
1382
+ void GUIFormSpecMenu::parseListColors (parserData* data,std::string element) {
1383
+ std::vector<std::string> parts = split (element,' ;' );
1384
+
1385
+ if (parts.size () == 2 ) || (parts.size () == 3 ) || (parts.size () == 5 )) {
1386
+ parseColor (parts[0 ], m_slotbg_n, false );
1387
+ parseColor (parts[1 ], m_slotbg_h, false );
1388
+
1389
+ if (parts.size () >= 3 ) {
1390
+ if (parseColor (parts[2 ], m_slotbordercolor, false )) {
1391
+ m_slotborder = true ;
1392
+ }
1393
+ }
1394
+ if (parts.size () == 5 ) {
1395
+ video::SColor tmp_color;
1396
+
1397
+ if (parseColor (parts[3 ], tmp_color, false ))
1398
+ m_tooltip_element->setBackgroundColor (tmp_color);
1399
+ if (parseColor (parts[4 ], tmp_color, false ))
1400
+ m_tooltip_element->setOverrideColor (tmp_color);
1401
+ }
1402
+ return ;
1403
+ }
1404
+ errorstream<< " Invalid listcolors element(" << parts.size () << " ): '" << element << " '" << std::endl;
1405
+ }
1406
+
1360
1407
void GUIFormSpecMenu::parseElement (parserData* data,std::string element) {
1361
1408
1362
1409
// some prechecks
@@ -1467,6 +1514,16 @@ void GUIFormSpecMenu::parseElement(parserData* data,std::string element) {
1467
1514
return ;
1468
1515
}
1469
1516
1517
+ if (type == " bgcolor" ) {
1518
+ parseBackgroundColor (data,description);
1519
+ return ;
1520
+ }
1521
+
1522
+ if (type == " listcolors" ) {
1523
+ parseListColors (data,description);
1524
+ return ;
1525
+ }
1526
+
1470
1527
// Ignore others
1471
1528
infostream
1472
1529
<< " Unknown DrawSpec: type=" <<type<<" , data=\" " <<description<<" \" "
@@ -1537,25 +1594,39 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
1537
1594
m_fields.clear ();
1538
1595
m_boxes.clear ();
1539
1596
1597
+ // Set default values (fits old formspec values)
1598
+ m_bgcolor = video::SColor (140 ,0 ,0 ,0 );
1599
+ m_bgfullscreen = false ;
1600
+
1601
+ m_slotbg_n = video::SColor (255 ,128 ,128 ,128 );
1602
+ m_slotbg_h = video::SColor (255 ,192 ,192 ,192 );
1603
+
1604
+ m_slotbordercolor = video::SColor (200 ,0 ,0 ,0 );
1605
+ m_slotborder = false ;
1606
+
1607
+ m_clipbackground = false ;
1608
+ // Add tooltip
1609
+ {
1610
+ // Note: parent != this so that the tooltip isn't clipped by the menu rectangle
1611
+ m_tooltip_element = Environment->addStaticText (L" " ,core::rect<s32>(0 ,0 ,110 ,18 ));
1612
+ m_tooltip_element->enableOverrideColor (true );
1613
+ m_tooltip_element->setBackgroundColor (video::SColor (255 ,110 ,130 ,60 ));
1614
+ m_tooltip_element->setDrawBackground (true );
1615
+ m_tooltip_element->setDrawBorder (true );
1616
+ m_tooltip_element->setOverrideColor (video::SColor (255 ,255 ,255 ,255 ));
1617
+ m_tooltip_element->setTextAlignment (gui::EGUIA_CENTER, gui::EGUIA_CENTER);
1618
+ m_tooltip_element->setWordWrap (false );
1619
+ // we're not parent so no autograb for this one!
1620
+ m_tooltip_element->grab ();
1621
+ }
1622
+
1540
1623
1541
1624
std::vector<std::string> elements = split (m_formspec_string,' ]' );
1542
1625
1543
1626
for (unsigned int i=0 ;i< elements.size ();i++) {
1544
1627
parseElement (&mydata,elements[i]);
1545
1628
}
1546
1629
1547
- // If there's inventory, put the usage string at the bottom
1548
- if (m_inventorylists.size ())
1549
- {
1550
- changeCtype (" " );
1551
- core::rect<s32> rect (0 , 0 , mydata.size .X -padding.X *2 , mydata.helptext_h );
1552
- rect = rect + v2s32 ((mydata.size .X /2 - mydata.rect .getWidth ()/2 ) +5 ,
1553
- mydata.size .Y -5 -mydata.helptext_h );
1554
- const wchar_t *text = wgettext (" Left click: Move all items, Right click: Move single item" );
1555
- Environment->addStaticText (text, rect, false , true , this , 256 );
1556
- delete[] text;
1557
- changeCtype (" C" );
1558
- }
1559
1630
// If there's fields, add a Proceed button
1560
1631
if (m_fields.size () && mydata.bp_set != 2 )
1561
1632
{
@@ -1583,20 +1654,6 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
1583
1654
}
1584
1655
changeCtype (" C" );
1585
1656
}
1586
- // Add tooltip
1587
- {
1588
- // Note: parent != this so that the tooltip isn't clipped by the menu rectangle
1589
- m_tooltip_element = Environment->addStaticText (L" " ,core::rect<s32>(0 ,0 ,110 ,18 ));
1590
- m_tooltip_element->enableOverrideColor (true );
1591
- m_tooltip_element->setBackgroundColor (video::SColor (255 ,110 ,130 ,60 ));
1592
- m_tooltip_element->setDrawBackground (true );
1593
- m_tooltip_element->setDrawBorder (true );
1594
- m_tooltip_element->setOverrideColor (video::SColor (255 ,255 ,255 ,255 ));
1595
- m_tooltip_element->setTextAlignment (gui::EGUIA_CENTER, gui::EGUIA_CENTER);
1596
- m_tooltip_element->setWordWrap (false );
1597
- // we're not parent so no autograb for this one!
1598
- m_tooltip_element->grab ();
1599
- }
1600
1657
1601
1658
// set initial focus if parser didn't set it
1602
1659
focused_element = Environment->getFocus ();
@@ -1681,16 +1738,31 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
1681
1738
1682
1739
if (phase == 0 )
1683
1740
{
1684
- if (hovering && m_selected_item)
1685
- {
1686
- video::SColor bgcolor (255 ,192 ,192 ,192 );
1687
- driver->draw2DRectangle (bgcolor, rect, &AbsoluteClippingRect);
1688
- }
1741
+ if (hovering)
1742
+ driver->draw2DRectangle (m_slotbg_h, rect, &AbsoluteClippingRect);
1689
1743
else
1690
- {
1691
- video::SColor bgcolor (255 ,128 ,128 ,128 );
1692
- driver->draw2DRectangle (bgcolor, rect, &AbsoluteClippingRect);
1693
- }
1744
+ driver->draw2DRectangle (m_slotbg_n, rect, &AbsoluteClippingRect);
1745
+ }
1746
+
1747
+ // Draw inv slot borders
1748
+ if (m_slotborder) {
1749
+ s32 x1 = rect.UpperLeftCorner .X ;
1750
+ s32 y1 = rect.UpperLeftCorner .Y ;
1751
+ s32 x2 = rect.LowerRightCorner .X ;
1752
+ s32 y2 = rect.LowerRightCorner .Y ;
1753
+ s32 border = 1 ;
1754
+ driver->draw2DRectangle (m_slotbordercolor,
1755
+ core::rect<s32>(v2s32 (x1 - border, y1 - border),
1756
+ v2s32 (x2 + border, y1 )), NULL );
1757
+ driver->draw2DRectangle (m_slotbordercolor,
1758
+ core::rect<s32>(v2s32 (x1 - border, y2),
1759
+ v2s32 (x2 + border, y2 + border)), NULL );
1760
+ driver->draw2DRectangle (m_slotbordercolor,
1761
+ core::rect<s32>(v2s32 (x1 - border, y1 ),
1762
+ v2s32 (x1, y2)), NULL );
1763
+ driver->draw2DRectangle (m_slotbordercolor,
1764
+ core::rect<s32>(v2s32 (x2, y1 ),
1765
+ v2s32 (x2 + border, y2)), NULL );
1694
1766
}
1695
1767
1696
1768
if (phase == 1 )
@@ -1771,8 +1843,12 @@ void GUIFormSpecMenu::drawMenu()
1771
1843
return ;
1772
1844
video::IVideoDriver* driver = Environment->getVideoDriver ();
1773
1845
1774
- video::SColor bgcolor (140 ,0 ,0 ,0 );
1775
- driver->draw2DRectangle (bgcolor, AbsoluteRect, &AbsoluteClippingRect);
1846
+ v2u32 screenSize = driver->getScreenSize ();
1847
+ core::rect<s32> allbg (0 , 0 , screenSize.X , screenSize.Y );
1848
+ if (m_bgfullscreen)
1849
+ driver->draw2DRectangle (m_bgcolor, allbg, &allbg);
1850
+ else
1851
+ driver->draw2DRectangle (m_bgcolor, AbsoluteRect, &AbsoluteClippingRect);
1776
1852
1777
1853
m_tooltip_element->setVisible (false );
1778
1854
@@ -1789,6 +1865,15 @@ void GUIFormSpecMenu::drawMenu()
1789
1865
core::rect<s32> imgrect (0 , 0 , spec.geom .X , spec.geom .Y );
1790
1866
// Image rectangle on screen
1791
1867
core::rect<s32> rect = imgrect + spec.pos ;
1868
+
1869
+ if (m_clipbackground) {
1870
+ core::dimension2d<s32> absrec_size = AbsoluteRect.getSize ();
1871
+ rect = core::rect<s32>(AbsoluteRect.UpperLeftCorner .X - spec.pos .X ,
1872
+ AbsoluteRect.UpperLeftCorner .Y - spec.pos .Y ,
1873
+ AbsoluteRect.UpperLeftCorner .X + absrec_size.Width + spec.pos .X *2 ,
1874
+ AbsoluteRect.UpperLeftCorner .Y + absrec_size.Height + spec.pos .Y *2 );
1875
+ }
1876
+
1792
1877
const video::SColor color (255 ,255 ,255 ,255 );
1793
1878
const video::SColor colors[] = {color,color,color,color};
1794
1879
driver->draw2DImage (texture, rect,
@@ -1880,10 +1965,8 @@ void GUIFormSpecMenu::drawMenu()
1880
1965
Draw items
1881
1966
Phase 0: Item slot rectangles
1882
1967
Phase 1: Item images; prepare tooltip
1883
- If backgrounds used, do not draw Item slot rectangles
1884
1968
*/
1885
1969
int start_phase=0 ;
1886
- if (m_backgrounds.size () > 0 ) start_phase=1 ;
1887
1970
for (int phase=start_phase; phase<=1 ; phase++)
1888
1971
for (u32 i=0 ; i<m_inventorylists.size (); i++)
1889
1972
{
@@ -2643,18 +2726,78 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
2643
2726
return Parent ? Parent->OnEvent (event) : false ;
2644
2727
}
2645
2728
2646
- bool GUIFormSpecMenu::parseColor (std::string color, irr::video::SColor& outcolor) {
2647
- outcolor = irr::video::SColor (0 ,0 ,0 ,0 );
2648
-
2649
- if (!string_allowed (color, " 0123456789abcdefABCDEF" ))
2729
+ static inline bool hex_digit_decode (char hexdigit, unsigned char &value)
2730
+ {
2731
+ if (hexdigit >= ' 0' && hexdigit <= ' 9' )
2732
+ value = hexdigit - ' 0' ;
2733
+ else if (hexdigit >= ' A' && hexdigit <= ' F' )
2734
+ value = hexdigit - ' A' + 10 ;
2735
+ else if (hexdigit >= ' a' && hexdigit <= ' f' )
2736
+ value = hexdigit - ' a' + 10 ;
2737
+ else
2650
2738
return false ;
2739
+ return true ;
2740
+ }
2651
2741
2652
- u32 color_value;
2653
- std::istringstream iss (color);
2654
- iss >> std::hex >> color_value;
2655
-
2656
- outcolor = irr::video::SColor (color_value);
2742
+ bool GUIFormSpecMenu::parseColor (std::string &value, video::SColor &color, bool quiet)
2743
+ {
2744
+ const char *hexpattern = NULL ;
2745
+ if (value[0 ] == ' #' ) {
2746
+ if (value.size () == 9 )
2747
+ hexpattern = " #RRGGBBAA" ;
2748
+ else if (value.size () == 7 )
2749
+ hexpattern = " #RRGGBB" ;
2750
+ else if (value.size () == 5 )
2751
+ hexpattern = " #RGBA" ;
2752
+ else if (value.size () == 4 )
2753
+ hexpattern = " #RGB" ;
2754
+ }
2755
+
2756
+ if (hexpattern) {
2757
+ assert (strlen (hexpattern) == value.size ());
2758
+ video::SColor outcolor (255 , 255 , 255 , 255 );
2759
+ for (size_t pos = 0 ; pos < value.size (); ++pos) {
2760
+ // '#' in the pattern means skip that character
2761
+ if (hexpattern[pos] == ' #' )
2762
+ continue ;
2657
2763
2658
- outcolor.setAlpha (255 );
2659
- return true ;
2764
+ // Else assume hexpattern[pos] is one of 'R' 'G' 'B' 'A'
2765
+ // Read one or two digits, depending on hexpattern
2766
+ unsigned char c1, c2;
2767
+ if (hexpattern[pos+1 ] == hexpattern[pos]) {
2768
+ // Two digits, e.g. hexpattern == "#RRGGBB"
2769
+ if (!hex_digit_decode (value[pos], c1) ||
2770
+ !hex_digit_decode (value[pos+1 ], c2))
2771
+ goto fail;
2772
+ ++pos;
2773
+ }
2774
+ else {
2775
+ // One digit, e.g. hexpattern == "#RGB"
2776
+ if (!hex_digit_decode (value[pos], c1))
2777
+ goto fail;
2778
+ c2 = c1;
2779
+ }
2780
+ u32 colorpart = ((c1 & 0x0f ) << 4 ) | (c2 & 0x0f );
2781
+
2782
+ // Update outcolor with newly read color part
2783
+ if (hexpattern[pos] == ' R' )
2784
+ outcolor.setRed (colorpart);
2785
+ else if (hexpattern[pos] == ' G' )
2786
+ outcolor.setGreen (colorpart);
2787
+ else if (hexpattern[pos] == ' B' )
2788
+ outcolor.setBlue (colorpart);
2789
+ else if (hexpattern[pos] == ' A' )
2790
+ outcolor.setAlpha (colorpart);
2791
+ }
2792
+
2793
+ color = outcolor;
2794
+ return true ;
2795
+ }
2796
+
2797
+ // Optionally, named colors could be implemented here
2798
+
2799
+ fail:
2800
+ if (!quiet)
2801
+ errorstream<<" Invalid color: \" " <<value<<" \" " <<std::endl;
2802
+ return false ;
2660
2803
}
0 commit comments