Programming 2D Games

The official forum for "Programming 2D Games" the book by: Charles Kelly

It is currently Thu Oct 18, 2018 11:31 pm

All times are UTC




Post new topic Reply to topic  [ 2 posts ] 
Author Message
PostPosted: Thu Jan 04, 2018 4:33 am 
Offline

Joined: Thu Oct 05, 2017 6:53 am
Posts: 13
In my game, I modified the `messageDialog` to allow for more than 2 buttons, and I modified the `inputDialog` to allow for more than 1 input box.

I'm not sure the best way to present all the changes, so I will include a diff.
I apologize this post is going to be bit lengthy.

Here is a diff of messageDialog.h:
Code:
diff --git a/messageDialog.h b/messageDialog.h
index 4e3bb64..bbee758 100755
--- a/messageDialog.h
+++ b/messageDialog.h
@@ -10,6 +10,8 @@
 class MessageDialog;
 
 #include <string>
+#include <vector>
+#include <algorithm>
 #include "constants.h"
 #include "textDX.h"
 #include "graphics.h"
@@ -24,19 +26,33 @@ namespace messageDialogNS
     const char FONT[] = "Arial";        // font
     const int FONT_HEIGHT = 18;         // font height
     const COLOR_ARGB FONT_COLOR = graphicsNS::WHITE;        // text color
-    const COLOR_ARGB BORDER_COLOR = D3DCOLOR_ARGB(192,192,192,192); // border color
-    const COLOR_ARGB BACK_COLOR = SETCOLOR_ARGB(255,100,100,192);   // backdrop color
-    const UINT X = GAME_WIDTH/4;        // default location
-    const UINT Y = GAME_HEIGHT/4;
-    const UINT BUTTON_WIDTH = (UINT)(FONT_HEIGHT * 4.5);
+    const COLOR_ARGB BORDER_COLOR = D3DCOLOR_ARGB(128,192,192,192); // border color
+    const COLOR_ARGB BACK_COLOR = SETCOLOR_ARGB(128,100,100,192);   // backdrop color
+    const UINT X = GAME_WIDTH/2 - WIDTH/2;        // default location
+    const UINT Y = GAME_HEIGHT/2 - HEIGHT/2;
+    const UINT BUTTON_WIDTH = (UINT)(FONT_HEIGHT * 5.0);
     const UINT BUTTON_HEIGHT = FONT_HEIGHT + 4;
-    const int MAX_TYPE = 2;
+    const int MAX_BUTTONS_PER_ROW = 6;
+    const int MAX_TYPE = 4;
     const int OK_CANCEL = 0;            // OK Cancel button type
     const int YES_NO = 1;               // Yes No button type
-    static const char* BUTTON1_TEXT[MAX_TYPE] = {"OK", "YES"};
-    static const char* BUTTON2_TEXT[MAX_TYPE] = {"CANCEL", "NO"};
+    const int EDIT_OBJECT = 2;
+    const int CREATE_OBJECT = 3;
+    static const UINT NUM_BUTTONS[MAX_TYPE] = {2, 2, 6, 12};
+    static const char* BUTTON1_TEXT[MAX_TYPE]  = { "OK",     "YES", "APPLY",     "DOOR" };
+    static const char* BUTTON2_TEXT[MAX_TYPE]  = { "CANCEL", "NO",  "DUPLICATE", "OUTLET" };
+    static const char* BUTTON3_TEXT[MAX_TYPE]  = { "",        "",   "DELETE",    "FLOOR" };
+    static const char* BUTTON4_TEXT[MAX_TYPE]  = { "",        "",   "SAVE",      "WALL" };
+    static const char* BUTTON5_TEXT[MAX_TYPE]  = { "",        "",   "RESET",     "SWITCH" };
+    static const char* BUTTON6_TEXT[MAX_TYPE]  = { "",        "",   "QUIT",      "BUTTON" };
+    static const char* BUTTON7_TEXT[MAX_TYPE]  = { "",        "",   "",          "CRATE" };
+    static const char* BUTTON8_TEXT[MAX_TYPE]  = { "",        "",   "",          "PAGE" };
+    static const char* BUTTON9_TEXT[MAX_TYPE]  = { "",        "",   "",          "SPIKE" };
+    static const char* BUTTON10_TEXT[MAX_TYPE] = { "",        "",   "",          "WATER" };
+    static const char* BUTTON11_TEXT[MAX_TYPE] = { "",        "",   "",          "CONVEYOR" };
+    static const char* BUTTON12_TEXT[MAX_TYPE] = { "",        "",   "",          "CRUSHER" };
     const byte DIALOG_CLOSE_KEY = VK_RETURN;    // Enter key
-    const COLOR_ARGB BUTTON_COLOR = graphicsNS::GRAY;       // button background
+    const COLOR_ARGB BUTTON_COLOR = graphicsNS::DKGRAY;       // button background
     const COLOR_ARGB BUTTON_FONT_COLOR = graphicsNS::WHITE; // button text color
 }
 
@@ -52,8 +68,9 @@ protected:
     UINT        width;                  // dialog width
     std::string text;                   // dialog text
     RECT        textRect;               // text rectangle
-    RECT        buttonRect;             // button rectangle
-    RECT        button2Rect;            // button2 rectangle
+    //RECT        buttonRect;             // button rectangle
+    //RECT        button2Rect;            // button2 rectangle
+    std::vector<RECT> buttonRects;
     COLOR_ARGB  fontColor;              // font color (a,r,g,b)
     COLOR_ARGB  borderColor;            // border color (a,r,g,b)
     COLOR_ARGB  backColor;              // background color (a,r,g,b)
@@ -62,8 +79,9 @@ protected:
     VertexC vtx[4];                     // vertex data
     LP_VERTEXBUFFER dialogVerts;        // dialog vertex buffer
     LP_VERTEXBUFFER borderVerts;        // border vertex buffer
-    LP_VERTEXBUFFER buttonVerts;        // button vertex buffer
-    LP_VERTEXBUFFER button2Verts;       // button2 vertex buffer
+    //LP_VERTEXBUFFER buttonVerts;        // button vertex buffer
+    //LP_VERTEXBUFFER button2Verts;       // button2 vertex buffer
+    std::vector<LP_VERTEXBUFFER> buttonVerts;
     int buttonClicked;                  // which button was clicked (1 or 2)
     int buttonType;                     // 0 = OK/Cancel, 1 = Yes/No
     bool    initialized;                // true when initialized successfully
@@ -89,6 +107,8 @@ public:
     // Display the MessageDialog.
     const void draw();
 
+    void clearButtonClicked() { buttonClicked = 0; }
+
     // Return button clicked
     // 0 = no button clicked
     // 1 is left button, 2 is right button
@@ -97,6 +117,21 @@ public:
     // Return visible.
     bool getVisible() {return visible;}
 
+    // Get x position
+    float getX() { return x; }
+
+    // Get y position
+    float getY() { return y; }
+
+    // Get width
+    UINT getWidth() { return width; }
+   
+    // Get height
+    UINT getHeight() { return height; }
+
+    // Set position
+    void setPosition(float _x, float _y)  {x = _x; y = _y;}
+
     // Set font color
     void setFontColor(COLOR_ARGB fc)    {fontColor = fc;}
 
@@ -118,8 +153,18 @@ public:
     // Set button type 0 = OK/CANCEL, 1 = YES/NO
     void setButtonType(UINT t)
     {
-        if(t < messageDialogNS::MAX_TYPE)
+        if (t < messageDialogNS::MAX_TYPE) {
             buttonType = t;
+            UINT numButtons = messageDialogNS::NUM_BUTTONS[buttonType];
+            if (numButtons > messageDialogNS::MAX_BUTTONS_PER_ROW) {
+                width = (int)(messageDialogNS::BUTTON_WIDTH * 1.1f * messageDialogNS::MAX_BUTTONS_PER_ROW) + messageDialogNS::MARGIN * 2;
+            }
+            else {
+                width = (int)(messageDialogNS::BUTTON_WIDTH * 1.1f * numButtons) + messageDialogNS::MARGIN * 2;
+            }
+            if (width < messageDialogNS::WIDTH)
+                width = messageDialogNS::WIDTH;
+        }
     }
 
     // Display text str in MessageDialog

Some notes:
I changed the default location to the center of the screen.
I added a constant called `MAX_BUTTONS_PER_ROW` which is easily customizable.
I replaced `buttonRect` and `button2Rect` with `std::vector<RECT> buttonRects`.
I replaced `buttonVerts` and `button2Verts` with `std::vector<LP_VERTEXBUFFER> buttonVerts`.
I added functions for resetting the `buttonClicked`, getting the coordinates and dimensions, and for setting the coordinates.
The width of the dialog is calculated based on the number of buttons for the current `buttonType`.


Here is a diff of messageDialog.cpp:
Code:
diff --git a/messageDialog.cpp b/messageDialog.cpp
index 877156c..82e6bb1 100755
--- a/messageDialog.cpp
+++ b/messageDialog.cpp
@@ -28,8 +28,8 @@ MessageDialog::MessageDialog()
     textRect.top = messageDialogNS::Y + messageDialogNS::MARGIN;
     dialogVerts = NULL;
     borderVerts = NULL;
-    buttonVerts = NULL;
-    button2Verts = NULL;
+    //buttonVerts = NULL;
+    //button2Verts = NULL;
     buttonType = 0;     // OK/Cancel
 }
 
@@ -69,10 +69,16 @@ bool MessageDialog::initialize(Graphics *g, Input *in, HWND h)
 //=============================================================================
 void MessageDialog::prepareVerts()
 {
+    buttonRects.clear();
+
     safeRelease(dialogVerts);
     safeRelease(borderVerts);
-    safeRelease(buttonVerts);
-    safeRelease(button2Verts);
+    //safeRelease(buttonVerts);
+    //safeRelease(button2Verts);
+    for (LP_VERTEXBUFFER verts : buttonVerts) {
+        safeRelease(verts);
+    }
+    buttonVerts.clear();
 
     // border top left
     vtx[0].x = x;
@@ -134,73 +140,52 @@ void MessageDialog::prepareVerts()
 
     graphics->createVertexBuffer(vtx, sizeof vtx, dialogVerts);
 
-    // button top left
-    vtx[0].x = x + width/2.0f - messageDialogNS::BUTTON_WIDTH/2.0f;
-    vtx[0].y = y + height - messageDialogNS::BORDER - messageDialogNS::MARGIN - messageDialogNS::BUTTON_HEIGHT;
-    vtx[0].z = 0.0f;
-    vtx[0].rhw = 1.0f;
-    vtx[0].color = buttonColor;
-
-    // button top right
-    vtx[1].x = x + width/2.0f + messageDialogNS::BUTTON_WIDTH/2.0f;
-    vtx[1].y = vtx[0].y;
-    vtx[1].z = 0.0f;
-    vtx[1].rhw = 1.0f;
-    vtx[1].color = buttonColor;
-
-    // button bottom right
-    vtx[2].x =  vtx[1].x;
-    vtx[2].y = vtx[0].y + messageDialogNS::BUTTON_HEIGHT;
-    vtx[2].z = 0.0f;
-    vtx[2].rhw = 1.0f;
-    vtx[2].color = buttonColor;
-
-    // button bottom left
-    vtx[3].x = vtx[0].x;
-    vtx[3].y = vtx[2].y;
-    vtx[3].z = 0.0f;
-    vtx[3].rhw = 1.0f;
-    vtx[3].color = buttonColor;
-
-    graphics->createVertexBuffer(vtx, sizeof vtx, buttonVerts);
-
-    // set buttonRect
-    buttonRect.left   = (long)vtx[0].x;
-    buttonRect.right  = (long)vtx[1].x;
-    buttonRect.top    = (long)vtx[0].y;
-    buttonRect.bottom = (long)vtx[2].y;
-
-    // button2 top left
-    vtx[0].x = x + width - messageDialogNS::BUTTON_WIDTH*1.2f;
-    vtx[0].y = y + height - messageDialogNS::BORDER - messageDialogNS::MARGIN - messageDialogNS::BUTTON_HEIGHT;
-    vtx[0].z = 0.0f;
-    vtx[0].rhw = 1.0f;
-    vtx[0].color = buttonColor;
-    // button2 top right
-    vtx[1].x = vtx[0].x + messageDialogNS::BUTTON_WIDTH;
-    vtx[1].y = vtx[0].y;
-    vtx[1].z = 0.0f;
-    vtx[1].rhw = 1.0f;
-    vtx[1].color = buttonColor;
-    // button2 bottom right
-    vtx[2].x =  vtx[1].x;
-    vtx[2].y = vtx[0].y + messageDialogNS::BUTTON_HEIGHT;
-    vtx[2].z = 0.0f;
-    vtx[2].rhw = 1.0f;
-    vtx[2].color = buttonColor;
-    // button2 bottom left
-    vtx[3].x = vtx[0].x;
-    vtx[3].y = vtx[2].y;
-    vtx[3].z = 0.0f;
-    vtx[3].rhw = 1.0f;
-    vtx[3].color = buttonColor;
-    graphics->createVertexBuffer(vtx, sizeof vtx, button2Verts);
-
-    // set button2Rect
-    button2Rect.left   = (long)vtx[0].x;
-    button2Rect.right  = (long)vtx[1].x;
-    button2Rect.top    = (long)vtx[0].y;
-    button2Rect.bottom = (long)vtx[2].y;
+    int numButtons = messageDialogNS::NUM_BUTTONS[buttonType];
+    for (int i = 0; i < numButtons; ++i) {
+        int xOff = (int)(messageDialogNS::BUTTON_WIDTH * 1.1f * (i % messageDialogNS::MAX_BUTTONS_PER_ROW)) + messageDialogNS::MARGIN * 2;
+        if (numButtons <= messageDialogNS::MAX_BUTTONS_PER_ROW) {
+            xOff = width - ((numButtons - i) * (int)(messageDialogNS::BUTTON_WIDTH * 1.1f));
+        }
+        int yOff = (-1 * (int)(messageDialogNS::BUTTON_HEIGHT * 1.4f)) *
+                       (((numButtons - 1) / messageDialogNS::MAX_BUTTONS_PER_ROW + 1) -
+                       (i) / messageDialogNS::MAX_BUTTONS_PER_ROW);
+
+        // button top left
+        vtx[0].x = x + xOff;
+        vtx[0].y = y + height - messageDialogNS::BORDER - messageDialogNS::MARGIN + yOff;
+        vtx[0].z = 0.0f;
+        vtx[0].rhw = 1.0f;
+        vtx[0].color = buttonColor;
+
+        // button top right
+        vtx[1].x = vtx[0].x + messageDialogNS::BUTTON_WIDTH;
+        vtx[1].y = vtx[0].y;
+        vtx[1].z = 0.0f;
+        vtx[1].rhw = 1.0f;
+        vtx[1].color = buttonColor;
+
+        // button bottom right
+        vtx[2].x = vtx[1].x;
+        vtx[2].y = vtx[0].y + messageDialogNS::BUTTON_HEIGHT;
+        vtx[2].z = 0.0f;
+        vtx[2].rhw = 1.0f;
+        vtx[2].color = buttonColor;
+
+        // button bottom left
+        vtx[3].x = vtx[0].x;
+        vtx[3].y = vtx[2].y;
+        vtx[3].z = 0.0f;
+        vtx[3].rhw = 1.0f;
+        vtx[3].color = buttonColor;
+
+        buttonVerts.emplace_back();
+        graphics->createVertexBuffer(vtx, sizeof vtx, buttonVerts.back());
+
+        // set buttonRect
+        buttonRects.emplace_back();
+        buttonRects.back().left   = (long)vtx[0].x;
+        buttonRects.back().right  = (long)vtx[1].x;
+        buttonRects.back().top    = (long)vtx[0].y;
+        buttonRects.back().bottom = (long)vtx[2].y;
+    }
 }
 
 //=============================================================================
@@ -213,8 +198,11 @@ const void MessageDialog::draw()
 
     graphics->drawQuad(borderVerts);        // draw border
     graphics->drawQuad(dialogVerts);        // draw backdrop
-    graphics->drawQuad(buttonVerts);        // draw button
-    graphics->drawQuad(button2Verts);       // draw button2
+    //graphics->drawQuad(buttonVerts);        // draw button
+    //graphics->drawQuad(button2Verts);       // draw button2
+    for (LP_VERTEXBUFFER verts : buttonVerts) {
+        graphics->drawQuad(verts);
+    }
 
     graphics->spriteBegin();                // begin drawing sprites
 
@@ -226,10 +214,54 @@ const void MessageDialog::draw()
 
     // display text on buttons
     dxFont.setFontColor(buttonFontColor);
-    dxFont.print(messageDialogNS::BUTTON1_TEXT[buttonType],buttonRect,
-                 DT_SINGLELINE|DT_CENTER|DT_VCENTER);
-    dxFont.print(messageDialogNS::BUTTON2_TEXT[buttonType],button2Rect,
-                 DT_SINGLELINE|DT_CENTER|DT_VCENTER);
+    //dxFont.print(messageDialogNS::BUTTON1_TEXT[buttonType],buttonRect,
+    //             DT_SINGLELINE|DT_CENTER|DT_VCENTER);
+    //dxFont.print(messageDialogNS::BUTTON2_TEXT[buttonType],button2Rect,
+    //             DT_SINGLELINE|DT_CENTER|DT_VCENTER);
+    for (UINT i = 0; i < buttonRects.size(); ++i) {
+        const char** buttonText;
+        switch (i) {
+        case 0:
+            buttonText = messageDialogNS::BUTTON1_TEXT;
+            break;
+        case 1:
+            buttonText = messageDialogNS::BUTTON2_TEXT;
+            break;
+        case 2:
+            buttonText = messageDialogNS::BUTTON3_TEXT;
+            break;
+        case 3:
+            buttonText = messageDialogNS::BUTTON4_TEXT;
+            break;
+        case 4:
+            buttonText = messageDialogNS::BUTTON5_TEXT;
+            break;
+        case 5:
+            buttonText = messageDialogNS::BUTTON6_TEXT;
+            break;
+        case 6:
+            buttonText = messageDialogNS::BUTTON7_TEXT;
+            break;
+        case 7:
+            buttonText = messageDialogNS::BUTTON8_TEXT;
+            break;
+        case 8:
+            buttonText = messageDialogNS::BUTTON9_TEXT;
+            break;
+        case 9:
+            buttonText = messageDialogNS::BUTTON10_TEXT;
+            break;
+        case 10:
+            buttonText = messageDialogNS::BUTTON11_TEXT;
+            break;
+        case 11:
+            buttonText = messageDialogNS::BUTTON12_TEXT;
+            break;
+        }
+
+        dxFont.print(buttonText[buttonType], buttonRects[i],
+                     DT_SINGLELINE | DT_CENTER | DT_VCENTER);
+    }
 
     graphics->spriteEnd();                  // end drawing sprites
 }
@@ -241,12 +273,12 @@ void MessageDialog::update()
 {
     if (!initialized || !visible)
         return;
-    if (input->wasKeyPressed(messageDialogNS::DIALOG_CLOSE_KEY))
+    /*if (input->wasKeyPressed(messageDialogNS::DIALOG_CLOSE_KEY))
     {
         visible = false;
         buttonClicked = 1;              // button1 was clicked
         return;
-    }
+    }*/
 
     if (graphics->getFullscreen() == false) // if windowed
     {
@@ -257,10 +289,10 @@ void MessageDialog::update()
         screenRatioY = (float)GAME_HEIGHT / clientRect.bottom;
     }
 
-    if (input->getMouseLButton())       // if mouse left button
+    if (input->getMouseLButtonPressed())       // if mouse left button
     {
         // if mouse clicked inside button1 (OK)
-        if (input->getMouseX()*screenRatioX >= buttonRect.left &&
+        /*if (input->getMouseX()*screenRatioX >= buttonRect.left &&
             input->getMouseX()*screenRatioX <= buttonRect.right &&
             input->getMouseY()*screenRatioY >= buttonRect.top &&
             input->getMouseY()*screenRatioY <= buttonRect.bottom)
@@ -268,16 +300,27 @@ void MessageDialog::update()
             visible = false;            // hide message dialog
             buttonClicked = 1;          // button1 was clicked
             return;
-        }
+        }*/
 
         // if mouse clicked inside button2 (cancel)
-        if (input->getMouseX()*screenRatioX >= button2Rect.left &&
+        /*if (input->getMouseX()*screenRatioX >= button2Rect.left &&
             input->getMouseX()*screenRatioX <= button2Rect.right &&
             input->getMouseY()*screenRatioY >= button2Rect.top &&
             input->getMouseY()*screenRatioY <= button2Rect.bottom)
         {
             visible = false;            // hide message dialog
             buttonClicked = 2;          // button2 was clicked
+        }*/
+
+        for (UINT i = 0; i < buttonRects.size(); ++i) {
+            if (input->getMouseX()*screenRatioX >= buttonRects[i].left &&
+                input->getMouseX()*screenRatioX <= buttonRects[i].right &&
+                input->getMouseY()*screenRatioY >= buttonRects[i].top &&
+                input->getMouseY()*screenRatioY <= buttonRects[i].bottom)
+            {
+                visible = false;            // hide message dialog
+                buttonClicked = i + 1;          // button i was clicked
+            }
         }
     }
 }
@@ -293,7 +336,7 @@ void MessageDialog::print(const std::string &str)
 
     // Set textRect to text area of dialog
     textRect.left   = (long)(x + messageDialogNS::MARGIN);
-    textRect.right  = (long)(x + messageDialogNS::WIDTH - messageDialogNS::MARGIN);
+    textRect.right  = (long)(x + width - messageDialogNS::MARGIN);
     textRect.top    = (long)(y + messageDialogNS::MARGIN);
     textRect.bottom = (long)(y + messageDialogNS::HEIGHT - messageDialogNS::MARGIN);
 
@@ -301,6 +344,10 @@ void MessageDialog::print(const std::string &str)
     // No text is printed with DT_CALDRECT option.
     dxFont.print(text,textRect,DT_CENTER|DT_WORDBREAK|DT_CALCRECT);
     height = textRect.bottom - (int)y + messageDialogNS::BORDER + messageDialogNS::MARGIN;
+    UINT numButtons = messageDialogNS::NUM_BUTTONS[buttonType];
+    height += ((numButtons - 1) / messageDialogNS::MAX_BUTTONS_PER_ROW) * (int)(messageDialogNS::BUTTON_HEIGHT * 1.4f);
 
     prepareVerts();                 // prepare the vertex buffers
     buttonClicked = 0;              // clear buttonClicked
@@ -317,8 +364,12 @@ void MessageDialog::onLostDevice()
     dxFont.onLostDevice();
     safeRelease(dialogVerts);
     safeRelease(borderVerts);
-    safeRelease(buttonVerts);
-    safeRelease(button2Verts);
+    //safeRelease(buttonVerts);
+    //safeRelease(button2Verts);
+    for (LP_VERTEXBUFFER verts : buttonVerts) {
+        safeRelease(verts);
+    }
+    buttonVerts.clear();
 }
 
 //=============================================================================

Some notes:
The coordinates of each button vertex are calculated based on the "current row" of the button.
At least in my case, I am interested in having multiple dialogs on the screen at once, so I had to remove the bit about the `DIALOG_CLOSE_KEY`, because I don't want a key press to suddenly close every dialog at once.
I actually fixed a bug where you could close a dialog by holding the left mouse button down and passing the cursor over a button. I fixed this by adding a new function to input.cpp called `getMouseLButtonPressed()` which tells you if the left mouse button was just pressed this frame, as opposed to `getMouseLButton()` which tells you if the left mouse button is held. I call this new function here to detect if dialog buttons have been pressed.
The height of the dialog is calculated based on the number of rows of buttons.


Here is a diff of inputDialog.h:
Code:
diff --git a/inputDialog.h b/inputDialog.h
index ddd3718..0845516 100755
--- a/inputDialog.h
+++ b/inputDialog.h
@@ -10,6 +10,7 @@
 class InputDialog;
 
 #include <string>
+#include <vector>
 #include "constants.h"
 #include "textDX.h"
 #include "graphics.h"
@@ -18,20 +19,25 @@ class InputDialog;
 
 namespace inputDialogNS
 {
+    const COLOR_ARGB SELECTED_TEXT_BACK_COLOR = graphicsNS::YELLOW;
     const COLOR_ARGB TEXT_BACK_COLOR = graphicsNS::WHITE;   // input text background
     const COLOR_ARGB TEXT_COLOR = graphicsNS::BLACK;        // input text color
+    const int LABEL_WIDTH = 100;
 }
 
 // Input Dialog, inherits from Message Dialog
 class InputDialog : public MessageDialog
 {
 private:
-    std::string inText;                 // input text
-    RECT        inTextRect;
     RECT        tempRect;
-    COLOR_ARGB  textBackColor;          // text area background color
-    COLOR_ARGB  textFontColor;          // text area font color
-    LP_VERTEXBUFFER inTextVerts;        // text area vertex buffer
+    COLOR_ARGB  selectedTextBackColor;        // selected text area background color
+    COLOR_ARGB  textBackColor;                // text area background color
+    COLOR_ARGB  textFontColor;                // text area font color
+    std::vector<std::string> inText;          // input text
+    std::vector<RECT>        inTextRect;
+    std::vector<LP_VERTEXBUFFER> inTextVerts; // text area vertex buffer
+    std::vector<std::string> labels;
+    int selected;
 
 public:
     // Constructor
@@ -42,18 +48,58 @@ public:
     // Prepare vertex buffers
     void prepareVerts();
 
+    void addInputText(std::string label = "", std::string in = "") { labels.push_back(label); inText.push_back(in); }
+
     // Display the InputDialog.
     const void draw();
 
+    UINT getSize() { return inText.size(); }
+
     // Return input text.
     std::string getText()   
     {
-        if(!visible)
-            return inText;
+        if (!visible && selected >= 0)
+            return inText[selected];
         else
             return "";
     }
 
+    std::string getText(UINT i)
+    {
+        if (!visible && i < inText.size())
+            return inText[i];
+        else
+            return "";
+    }
+
+    int getSelected() { return selected; }
+
+    // Set input text
+    void setText(std::string t)
+    {
+        if (visible && selected >= 0) {
+            inText[selected] = t;
+            input->setTextIn(t);
+        }
+    }
+
+    void setText(UINT i, std::string t)
+    {
+        if (visible && i < inText.size()) {
+            inText[i] = t;
+            if (i == selected)
+                input->setTextIn(t);
+        }
+    }
+
+    void setSelected(int s)
+    {
+        if (s < (int)inText.size() && s != selected) {
+            selected = s;
+            prepareVerts();
+        }
+    }
+
     // Set input text font color
     void setTextFontColor(COLOR_ARGB fc)  {textFontColor = fc;}

Some notes:
I replaced `inText`, `inTextRect`, and `inTextVerts` with `std::vector`s.
I added `selectedTextBackColor` so that the currently selected input box can have a different color.
I added `std::vector<std::string> labels` to give each input box a label on its left side.



And lastly, here is a diff of inputDialog.cpp:
Code:
diff --git a/inputDialog.cpp b/inputDialog.cpp
index 11900cf..bbb475c 100755
--- a/inputDialog.cpp
+++ b/inputDialog.cpp
@@ -10,10 +10,12 @@
 //=============================================================================
 InputDialog::InputDialog()
 {
+    selectedTextBackColor = inputDialogNS::SELECTED_TEXT_BACK_COLOR;
     textBackColor = inputDialogNS::TEXT_BACK_COLOR;
     textFontColor = inputDialogNS::TEXT_COLOR;
-    inTextVerts = NULL;
-    inText = "";
+    //inTextVerts = NULL;
+    //inText = "";
+    selected = 0;
 }
 
 //=============================================================================
@@ -29,40 +31,52 @@ InputDialog::~InputDialog()
 //=============================================================================
 void InputDialog::prepareVerts()
 {
+    inTextRect.clear();
+
     MessageDialog::prepareVerts();  // call perpareVerts in base class
-    safeRelease(inTextVerts);
-
-    // inText top left
-    vtx[0].x = x + messageDialogNS::BORDER*2;
-    vtx[0].y = y + height - messageDialogNS::BORDER - messageDialogNS::MARGIN - messageDialogNS::BUTTON_HEIGHT*2.5f;
-    vtx[0].z = 0.0f;
-    vtx[0].rhw = 1.0f;
-    vtx[0].color = textBackColor;
-    // inText top right
-    vtx[1].x = x + width - messageDialogNS::BORDER*2;
-    vtx[1].y = vtx[0].y;
-    vtx[1].z = 0.0f;
-    vtx[1].rhw = 1.0f;
-    vtx[1].color = textBackColor;
-    // inText bottom right
-    vtx[2].x =  vtx[1].x;
-    vtx[2].y = vtx[0].y + messageDialogNS::BUTTON_HEIGHT;
-    vtx[2].z = 0.0f;
-    vtx[2].rhw = 1.0f;
-    vtx[2].color = textBackColor;
-    // inText bottom left
-    vtx[3].x = vtx[0].x;
-    vtx[3].y = vtx[2].y;
-    vtx[3].z = 0.0f;
-    vtx[3].rhw = 1.0f;
-    vtx[3].color = textBackColor;
-    graphics->createVertexBuffer(vtx, sizeof vtx, inTextVerts);
-
-    // set inTextRect
-    inTextRect.left   = (long)vtx[0].x;
-    inTextRect.right  = (long)vtx[1].x;
-    inTextRect.top    = (long)vtx[0].y;
-    inTextRect.bottom = (long)vtx[2].y;
+    //safeRelease(inTextVerts);
+    for (LP_VERTEXBUFFER verts : inTextVerts) {
+        safeRelease(verts);
+    }
+    inTextVerts.clear();
+
+    UINT numButtons = messageDialogNS::NUM_BUTTONS[buttonType];
+    for (UINT i = 0; i < inText.size(); ++i) {
+        COLOR_ARGB c = (i == selected ? selectedTextBackColor : textBackColor);
+        // inText top left
+        vtx[0].x = x + messageDialogNS::BORDER * 2 + inputDialogNS::LABEL_WIDTH;
+        vtx[0].y = y + height - messageDialogNS::BORDER - messageDialogNS::MARGIN
+                   - messageDialogNS::BUTTON_HEIGHT*1.5f * ((numButtons - 1) / messageDialogNS::MAX_BUTTONS_PER_ROW + 1)
+                   - (messageDialogNS::BUTTON_HEIGHT*1.2f) * (inText.size() - i);
+        vtx[0].z = 0.0f;
+        vtx[0].rhw = 1.0f;
+        vtx[0].color = c;
+        // inText top right
+        vtx[1].x = x + width - messageDialogNS::BORDER * 2;
+        vtx[1].y = vtx[0].y;
+        vtx[1].z = 0.0f;
+        vtx[1].rhw = 1.0f;
+        vtx[1].color = c;
+        // inText bottom right
+        vtx[2].x = vtx[1].x;
+        vtx[2].y = vtx[0].y + messageDialogNS::BUTTON_HEIGHT;
+        vtx[2].z = 0.0f;
+        vtx[2].rhw = 1.0f;
+        vtx[2].color = c;
+        // inText bottom left
+        vtx[3].x = vtx[0].x;
+        vtx[3].y = vtx[2].y;
+        vtx[3].z = 0.0f;
+        vtx[3].rhw = 1.0f;
+        vtx[3].color = c;
+
+        inTextVerts.emplace_back();
+        graphics->createVertexBuffer(vtx, sizeof vtx, inTextVerts.back());
+
+        // set inTextRect
+        inTextRect.emplace_back();
+        inTextRect.back().left = (long)vtx[0].x;
+        inTextRect.back().right = (long)vtx[1].x;
+        inTextRect.back().top = (long)vtx[0].y;
+        inTextRect.back().bottom = (long)vtx[2].y;
+    }
 }
 
 //=============================================================================
@@ -75,9 +89,15 @@ const void InputDialog::draw()
 
     graphics->drawQuad(borderVerts);        // draw border
     graphics->drawQuad(dialogVerts);        // draw backdrop
-    graphics->drawQuad(buttonVerts);        // draw button
-    graphics->drawQuad(button2Verts);       // draw button2
-    graphics->drawQuad(inTextVerts);        // draw input text area
+    //graphics->drawQuad(buttonVerts);        // draw button
+    //graphics->drawQuad(button2Verts);       // draw button2
+    for (LP_VERTEXBUFFER verts : buttonVerts) {
+        graphics->drawQuad(verts);
+    }
+    //graphics->drawQuad(inTextVerts);        // draw input text area
+    for (LP_VERTEXBUFFER verts : inTextVerts) {
+        graphics->drawQuad(verts);
+    }
 
     graphics->spriteBegin();                // begin drawing sprites
 
@@ -89,18 +109,52 @@ const void InputDialog::draw()
 
     // display text on buttons
     dxFont.setFontColor(buttonFontColor);
-    dxFont.print(messageDialogNS::BUTTON1_TEXT[buttonType],buttonRect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
-    dxFont.print(messageDialogNS::BUTTON2_TEXT[buttonType],button2Rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
+    //dxFont.print(messageDialogNS::BUTTON1_TEXT[buttonType],buttonRect,
+    //             DT_SINGLELINE|DT_CENTER|DT_VCENTER);
+    //dxFont.print(messageDialogNS::BUTTON2_TEXT[buttonType],button2Rect,
+    //             DT_SINGLELINE|DT_CENTER|DT_VCENTER);
+    for (UINT i = 0; i < buttonRects.size(); ++i) {
+        const char** buttonText;
+        switch (i) {
+        case 0:
+            buttonText = messageDialogNS::BUTTON1_TEXT;
+            break;
+        case 1:
+            buttonText = messageDialogNS::BUTTON2_TEXT;
+            break;
+        case 2:
+            buttonText = messageDialogNS::BUTTON3_TEXT;
+            break;
+        case 3:
+            buttonText = messageDialogNS::BUTTON4_TEXT;
+            break;
+        case 4:
+            buttonText = messageDialogNS::BUTTON5_TEXT;
+            break;
+        case 5:
+            buttonText = messageDialogNS::BUTTON6_TEXT;
+            break;
+        case 6:
+            buttonText = messageDialogNS::BUTTON7_TEXT;
+            break;
+        case 7:
+            buttonText = messageDialogNS::BUTTON8_TEXT;
+            break;
+        case 8:
+            buttonText = messageDialogNS::BUTTON9_TEXT;
+            break;
+        case 9:
+            buttonText = messageDialogNS::BUTTON10_TEXT;
+            break;
+        case 10:
+            buttonText = messageDialogNS::BUTTON11_TEXT;
+            break;
+        case 11:
+            buttonText = messageDialogNS::BUTTON12_TEXT;
+            break;
+        }
+
+        dxFont.print(buttonText[buttonType], buttonRects[i],
+            DT_SINGLELINE | DT_CENTER | DT_VCENTER);
+    }
 
     // display input text
-    dxFont.setFontColor(textFontColor);
-    tempRect = inTextRect;      // save
-    // No text is printed with DT_CALDRECT option. It moves RECT.right
-    dxFont.print(inText,tempRect,DT_SINGLELINE|DT_LEFT|DT_VCENTER|DT_CALCRECT);
-    if(tempRect.right > inTextRect.right)   // if text too long, right justify
-        dxFont.print(inText,inTextRect,DT_SINGLELINE|DT_RIGHT|DT_VCENTER);
-    else    // else, left justify
-        dxFont.print(inText,inTextRect,DT_SINGLELINE|DT_LEFT|DT_VCENTER);
+    for (UINT i = 0; i < inText.size(); ++i) {
+        dxFont.setFontColor(messageDialogNS::FONT_COLOR);
+        tempRect = inTextRect[i];
+        tempRect.left -= inputDialogNS::LABEL_WIDTH;
+        dxFont.print(labels[i], tempRect, DT_SINGLELINE | DT_LEFT | DT_VCENTER);
+        dxFont.setFontColor(textFontColor);
+        tempRect = inTextRect[i];      // save
+        // No text is printed with DT_CALDRECT option. It moves RECT.right
+        dxFont.print(inText[i], tempRect, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);
+        if (tempRect.right > inTextRect[i].right)   // if text too long, right justify
+            dxFont.print(inText[i], inTextRect[i], DT_SINGLELINE | DT_RIGHT | DT_VCENTER);
+        else    // else, left justify
+            dxFont.print(inText[i], inTextRect[i], DT_SINGLELINE | DT_LEFT | DT_VCENTER);
+    }
 
     graphics->spriteEnd();                  // end drawing sprites
 }
@@ -111,13 +165,35 @@ const void InputDialog::draw()
 void InputDialog::update()
 {
     MessageDialog::update();        // call update in base class
+    if (input->getMouseLButtonPressed())       // if mouse left button
+    {
+        for (UINT i = 0; i < inTextRect.size(); ++i) {
+            if (input->getMouseX()*screenRatioX >= inTextRect[i].left &&
+                input->getMouseX()*screenRatioX <= inTextRect[i].right &&
+                input->getMouseY()*screenRatioY >= inTextRect[i].top &&
+                input->getMouseY()*screenRatioY <= inTextRect[i].bottom)
+            {
+                selected = i;
+                prepareVerts();
+                input->setTextIn(inText[selected]);
+            }
+        }
+    }
+    if (visible && input->wasKeyPressed('\t')) {
+        selected = (selected + 1) % inText.size();
+        prepareVerts();
+        input->setTextIn(inText[selected]);
+    }
     if (!initialized || !visible)
     {
-        if(buttonClicked == 2)      // if Cancel button
-            inText = "";            // clear input text
+        if (buttonClicked == 2) {   // if Cancel button
+            for (UINT i = 0; i < inText.size(); ++i)
+                inText[i] = "";          // clear input text
+        }
         return;
     }
-    inText = input->getTextIn();    // get input text
+    if (selected >= 0)
+        inText[selected] = input->getTextIn();    // get input text
 }
 
 //=============================================================================
@@ -131,17 +207,18 @@ void InputDialog::print(const std::string &str)
 
     // Set textRect to text area of dialog
     textRect.left   = (long)(x + messageDialogNS::MARGIN);
-    textRect.right  = (long)(x + messageDialogNS::WIDTH - messageDialogNS::MARGIN);
+    textRect.right  = (long)(x + width - messageDialogNS::MARGIN);
     textRect.top    = (long)(y + messageDialogNS::MARGIN);
     textRect.bottom = (long)(y + messageDialogNS::HEIGHT - messageDialogNS::MARGIN);
 
     // Set textRect.bottom to precise height required for text
     // No text is printed with DT_CALDRECT option.
     dxFont.print(text,textRect,DT_CENTER|DT_WORDBREAK|DT_CALCRECT);
-    height = textRect.bottom - (int)y + messageDialogNS::BORDER + messageDialogNS::MARGIN;
+    height = textRect.bottom - (int)y + messageDialogNS::BORDER + messageDialogNS::MARGIN + (int)(messageDialogNS::BUTTON_HEIGHT*1.2f * (inText.size() - 1));
+    UINT numButtons = messageDialogNS::NUM_BUTTONS[buttonType];
+    height += ((numButtons - 1) / messageDialogNS::MAX_BUTTONS_PER_ROW) * (int)(messageDialogNS::BUTTON_HEIGHT * 1.4f);
 
     prepareVerts();                 // prepare the vertex buffers
-    inText = "";                    // clear old input
+    for (UINT i = 0; i < inText.size(); ++i)
+        inText[i] = "";                    // clear old input
     input->clearTextIn();
     buttonClicked = 0;              // clear buttonClicked
     visible = true;
@@ -155,6 +232,10 @@ void InputDialog::onLostDevice()
     if (!initialized)
         return;
     MessageDialog::onLostDevice();
-    safeRelease(inTextVerts);
+    //safeRelease(inTextVerts);
+    for (LP_VERTEXBUFFER verts : inTextVerts) {
+        safeRelease(verts);
+    }
+    inTextVerts.clear();
 }

Some notes:
The `draw()` function now draws a label to the left of the RECT for each input box.
The `update()` function looks for mouse clicks inside of an input box to change the currently selected input.
The `update()` function only adds new text input to the currently selected input.
The height of the dialog is calculated based on the number of inputs AND the number of rows of buttons.

With all of these changes, I was able to make my in-game level editor:
Image


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 04, 2018 1:48 pm 
Offline
Site Admin
User avatar

Joined: Sat Jan 28, 2012 4:36 pm
Posts: 547
Nice additions. I'll try to add them to the new game engine.

_________________
Professor Kelly


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 2 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group