commit c393c2566155bbad583ae096730cb4ace675192f
Author: david.sorber <david.sorber@gmail.com>
Date:   Fri Nov 28 13:22:07 2025 -0500

    Revamp display widgets. Use a listbox on the left panel and a multiline
    text box in the main right panel. Bump version to 0.2.0.

diff --git a/src/Catalog.cc b/src/Catalog.cc
index 4c2b3b3..fec712f 100644
--- a/src/Catalog.cc
+++ b/src/Catalog.cc
@@ -3,6 +3,7 @@
 #include <fstream>
 #include <iostream>
 #include <sstream>
+#include <stdexcept>
 
 #include <sodium.h>
 
@@ -13,8 +14,7 @@ Catalog::Catalog()
 {
     if (sodium_init() != 0)
     {
-        // TODO: throw exception here
-//        return 1;
+        throw std::runtime_error("libsodium init error!");
     }
 }
 
diff --git a/src/Catalog.h b/src/Catalog.h
index d979723..5eff2e6 100644
--- a/src/Catalog.h
+++ b/src/Catalog.h
@@ -35,6 +35,8 @@ class Catalog
 {
 public:
 
+    static inline CatalogItem INVALID_ITEM{"INVALID", "INVALID"};
+
     Catalog();
 
     ~Catalog();
@@ -60,6 +62,19 @@ public:
         return m_catalog.end();
     }
 
+    inline CatalogItem& getItemById(int id)
+    {
+        for (auto& iter : m_catalog)
+        {
+            if (iter.getId() == id)
+            {
+                return iter;
+            }
+        }
+
+        return INVALID_ITEM;
+    }
+
     void setAllVisible();
 
     void filter(const std::string& criteria);
diff --git a/src/CatalogItem.cc b/src/CatalogItem.cc
index 9a9f29b..e53e219 100644
--- a/src/CatalogItem.cc
+++ b/src/CatalogItem.cc
@@ -2,8 +2,12 @@
 
 #include "CatalogItem.h"
 
+// Initialize static member
+int CatalogItem::NEXT_ID(-1);
+
 CatalogItem::CatalogItem(const std::string& key, const std::string& value)
-    : m_key(key),
+    : m_id(NEXT_ID++),
+      m_key(key),
       m_keyLower(key),
       m_value(value),
       m_visible(true)
diff --git a/src/CatalogItem.h b/src/CatalogItem.h
index 669a08f..3764598 100644
--- a/src/CatalogItem.h
+++ b/src/CatalogItem.h
@@ -16,6 +16,11 @@ public:
 
     ~CatalogItem();
 
+    inline int getId() const
+    {
+        return m_id;
+    }
+
     inline const std::string& getKey() const
     {
         return m_key;
@@ -59,7 +64,6 @@ public:
         m_visible = vis;
     }
 
-
     /**
      * Return true if the specified criteria matches the key
      * @param criteria
@@ -70,6 +74,9 @@ public:
 
 private:
 
+    static int NEXT_ID;
+
+    int m_id;
     std::string m_key;
     std::string m_keyLower;
     std::string m_value;
@@ -77,9 +84,6 @@ private:
     char m_valueBuffer[VALUE_BUFFER_SIZE];
 
     bool m_visible;
-
-
-
 };
 
 
diff --git a/src/main.cc b/src/main.cc
index 1e74dce..7c84e13 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -33,7 +33,7 @@ namespace sfs = std::filesystem;
 #endif
 
 const std::string APP_NAME("pwmgr");
-const std::string VERSION("v0.1.5");
+const std::string VERSION("v0.2.0");
 const std::string DEFAULT_FILEPATH("/home/dsorber/Documents/chicken_soup/chicken_soup.txt.enc");
 
 const std::string BOLD{"\033[1m"};
@@ -182,6 +182,7 @@ int main(int argc, char** argv)
     // Main loop
     bool done = false;
     bool dataLoaded = false;
+
     bool loading = false;
     char filterBuffer[128]{};
     char filePathBuffer[BUFFER_SIZE]{};
@@ -199,9 +200,15 @@ int main(int argc, char** argv)
         std::memcpy(filePathBuffer, DEFAULT_FILEPATH.data(),
                     DEFAULT_FILEPATH.size());
     }
+    char passwdBuffer[BUFFER_SIZE]{};
     const char* statusText = STR_PWD;
 
-    char passwdBuffer[BUFFER_SIZE]{};
+    int selected_entry_idx = -1;
+    bool entry_highlight = false;
+    int entry_highlighted_idx = -1;
+    int selected = 0;
+    bool firstTime = true;
+
     while (! done)
     {
         // Poll and handle events (inputs, window resize, etc.)
@@ -417,27 +424,41 @@ int main(int argc, char** argv)
 
                 //---[Left side]----------------------------------------------------
                 ImGui::SetNextWindowPos(ImVec2(0.0f, 46.0f));
-                static int selected = 0;
-                static bool firstTime = true;
                 {
                     ImGui::BeginChild("left_pane", ImVec2(150, 0),
                                       ImGuiChildFlags_Borders |
-                                      ImGuiChildFlags_ResizeX);
+                                      ImGuiChildFlags_ResizeX,
+                                      ImGuiWindowFlags_NoScrollbar);
 
-                    for (auto &iter: catalog)
+                    ImVec2 contentRegionAvailable = ImGui::GetContentRegionAvail();
+                    float parentHeight = contentRegionAvailable.y;
+
+                    if (ImGui::BeginListBox("##entries_listbox",
+                                            ImVec2(-FLT_MIN, parentHeight)))
                     {
-                        // ImGuiInputTextFlags_ReadOnly
-                        if (iter.visible() &&
-                            ImGui::CollapsingHeader(iter.getKey().c_str()))
+                        for (auto &iter: catalog)
                         {
-                            ImGui::InputTextMultiline(
-                                    iter.getLcKey().c_str(),
-                                    iter.getValueBuffer(),
-                                    iter.getValueBufferSize(),
-                                    ImVec2(-FLT_MIN,
-                                             ImGui::GetTextLineHeight() * 5),
-                                    MULTILINE_TEXT_FLAGS);
+                            const bool is_selected = (selected_entry_idx == iter.getId());
+
+                            if (iter.visible())
+                            {
+                                if (ImGui::Selectable(iter.getKey().c_str(), is_selected))
+                                {
+                                    selected_entry_idx = iter.getId();
+                                }
+
+                                if (entry_highlight && ImGui::IsItemHovered())
+                                {
+                                    entry_highlighted_idx = iter.getId();
+                                }
+
+                                if (is_selected)
+                                {
+                                    ImGui::SetItemDefaultFocus();
+                                }
+                            }
                         }
+                        ImGui::EndListBox();
                     }
 
                     ImGui::EndChild();
@@ -475,33 +496,48 @@ int main(int argc, char** argv)
                     }
 
                     ImGui::Separator();
-                    if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None))
-                    {
-                        if (ImGui::BeginTabItem("Options"))
-                        {
-                            ImGui::TextWrapped(
-                                    "Lorem ipsum dolor sit amet, consectetur adipiscing "
-                                    "elit, sed do eiusmod tempor incididunt ut labore et"
-                                    " dolore magna aliqua. ");
-                            ImGui::EndTabItem();
-                        }
+                    ImGui::Text("Entry:");
+                    static char text[1024 * 16] = "foobarbizzle";
 
-                        if (ImGui::BeginTabItem("About"))
-                        {
-                            ImGui::Text("%s version: %s", APP_NAME.c_str(),
-                                        VERSION.c_str());
-                            ImGui::Text("Compiled on: %s ", __TIMESTAMP__);
-                            ImGui::Text("Created by: dsorber");
-                            ImGui::EndTabItem();
-                        }
-                        ImGui::EndTabBar();
+                    // Get the selected entry from the listbox on the left this will return
+                    // the INVALID_ITEM if the selected index is invalid
+                    CatalogItem& entry = catalog.getItemById(selected_entry_idx);
+                    if (entry.getId() == -1 || (! entry.visible()))
+                    {
+                        ImGui::InputTextMultiline("##entry_value",
+                                                  text,
+                                                  IM_ARRAYSIZE(text),
+                                                  ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16),
+                                                  ImGuiInputTextFlags_AllowTabInput);
+                    }
+                    else
+                    {
+                        // Display the selected entry's value
+                        ImGui::InputTextMultiline("##entry_value",
+                                                  entry.getValueBuffer(),
+                                                  entry.getValueBufferSize(),
+                                                  ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16),
+                                                  ImGuiInputTextFlags_AllowTabInput |
+                                                  ImGuiInputTextFlags_ReadOnly);
                     }
-                    ImGui::EndChild();
 
                     if (ImGui::Button("Save"))
                     {
-                        // I'll make this do something someday
+                        ImGui::OpenPopup("save_popup");
+                    }
+
+                    if (ImGui::BeginPopup("save_popup"))
+                    {
+                        ImGui::SeparatorText("Save Popup");
+                        ImGui::Text("Someday this button will do something...");
+                        ImGui::Text("but today is not that day");
+                        ImGui::PushFont(tinyfont);
+                        ImGui::Text("(click anywhere outside to close)");
+                        ImGui::PopFont();
+                        ImGui::EndPopup();
                     }
+
+                    ImGui::EndChild();
                     ImGui::EndGroup();
                 }
 
