Skip to content

Commit e6a8fa5

Browse files
committed
added documentation
1 parent e76555c commit e6a8fa5

File tree

1 file changed

+84
-63
lines changed

1 file changed

+84
-63
lines changed

config.cpp

+84-63
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,27 @@ struct ConfigSection {
1010
std::map<std::string, std::string> keyValues; // Key-value pairs
1111
};
1212

13+
/**
14+
* @class IniEditor
15+
* @brief A class to edit INI configuration files with a graphical user interface using SDL2.
16+
*
17+
* The IniEditor class provides a graphical interface for editing INI configuration files.
18+
* It uses SDL2 for rendering the UI and handling events, and SDL_ttf for text rendering.
19+
*
20+
* @details
21+
* The class supports loading and saving INI files, displaying sections and key-value pairs,
22+
* and providing tooltips for explanations of each configuration key. The user can interact
23+
* with the UI to select sections, edit values, and save changes.
24+
*
25+
* @note
26+
* - The class requires SDL2 and SDL_ttf libraries.
27+
* - The font file path is hardcoded to "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf".
28+
* - The class assumes a specific window size and layout for the UI elements.
29+
*
30+
* @example
31+
* IniEditor editor("config.ini");
32+
* editor.run();
33+
*/
1334
class IniEditor {
1435
SDL_Window* window = nullptr;
1536
SDL_Renderer* renderer = nullptr;
@@ -105,69 +126,69 @@ class IniEditor {
105126

106127
private:
107128
void loadIniFile(const std::string& filename) {
108-
std::ifstream file(filename);
129+
std::ifstream file(filename); // Open the INI file
109130
if (!file.is_open()) {
110-
std::cerr << "Failed to open " << filename << std::endl;
131+
std::cerr << "Failed to open " << filename << std::endl; // Error if file cannot be opened
111132
return;
112133
}
113134
std::string line;
114135
while (std::getline(file, line)) {
115136
line.erase(0, line.find_first_not_of(" \t")); // Trim leading whitespace
116137
if (line.empty() || line[0] == ';') continue; // Skip comments/blank lines
117-
if (line[0] == '[' && line.back() == ']') {
118-
currentSection = line.substr(1, line.size() - 2);
119-
sections.push_back(currentSection);
120-
iniData[currentSection] = ConfigSection();
121-
} else if (!currentSection.empty() && line.find('=') != std::string::npos) {
122-
auto pos = line.find('=');
123-
std::string key = line.substr(0, pos);
124-
std::string value = line.substr(pos + 1);
125-
key.erase(key.find_last_not_of(" \t") + 1); // Trim trailing whitespace
126-
value.erase(0, value.find_first_not_of(" \t")); // Trim leading whitespace
127-
iniData[currentSection].keyValues[key] = value;
138+
if (line[0] == '[' && line.back() == ']') { // Section header
139+
currentSection = line.substr(1, line.size() - 2); // Extract section name
140+
sections.push_back(currentSection); // Add section to list
141+
iniData[currentSection] = ConfigSection(); // Initialize section in map
142+
} else if (!currentSection.empty() && line.find('=') != std::string::npos) { // Key-value pair
143+
auto pos = line.find('='); // Find '=' character
144+
std::string key = line.substr(0, pos); // Extract key
145+
std::string value = line.substr(pos + 1); // Extract value
146+
key.erase(key.find_last_not_of(" \t") + 1); // Trim trailing whitespace from key
147+
value.erase(0, value.find_first_not_of(" \t")); // Trim leading whitespace from value
148+
iniData[currentSection].keyValues[key] = value; // Store key-value pair in current section
128149
}
129150
}
130-
file.close();
151+
file.close(); // Close the file
131152
}
132153

133154
void saveIniFile(const std::string& filename) {
134-
std::vector<std::string> lines;
135-
std::ifstream inFile(filename);
136-
if (!inFile.is_open()) {
155+
std::vector<std::string> lines; // Vector to store lines of the file
156+
std::ifstream inFile(filename); // Open the file for reading
157+
if (!inFile.is_open()) { // Check if the file is opened successfully
137158
std::cerr << "Failed to read " << filename << " for saving" << std::endl;
138159
return;
139160
}
140-
std::string line, currentSection;
141-
while (std::getline(inFile, line)) {
142-
std::string trimmed = line;
143-
trimmed.erase(0, trimmed.find_first_not_of(" \t"));
144-
if (trimmed.empty() || trimmed[0] == ';') {
145-
lines.push_back(line);
146-
} else if (trimmed[0] == '[' && trimmed.back() == ']') {
147-
currentSection = trimmed.substr(1, trimmed.size() - 2);
148-
lines.push_back(line);
149-
} else if (!currentSection.empty() && line.find('=') != std::string::npos) {
150-
auto pos = line.find('=');
151-
std::string key = line.substr(0, pos);
152-
key.erase(key.find_last_not_of(" \t") + 1);
153-
if (iniData[currentSection].keyValues.count(key)) {
154-
lines.push_back(key + " = " + iniData[currentSection].keyValues[key]);
161+
std::string line, currentSection; // Variables to store current line and section
162+
while (std::getline(inFile, line)) { // Read the file line by line
163+
std::string trimmed = line; // Copy the line to a new string
164+
trimmed.erase(0, trimmed.find_first_not_of(" \t")); // Trim leading whitespace
165+
if (trimmed.empty() || trimmed[0] == ';') { // Check if the line is empty or a comment
166+
lines.push_back(line); // Add the line to the vector
167+
} else if (trimmed[0] == '[' && trimmed.back() == ']') { // Check if the line is a section header
168+
currentSection = trimmed.substr(1, trimmed.size() - 2); // Extract the section name
169+
lines.push_back(line); // Add the section header to the vector
170+
} else if (!currentSection.empty() && line.find('=') != std::string::npos) { // Check if the line is a key-value pair
171+
auto pos = line.find('='); // Find the position of '='
172+
std::string key = line.substr(0, pos); // Extract the key
173+
key.erase(key.find_last_not_of(" \t") + 1); // Trim trailing whitespace from the key
174+
if (iniData[currentSection].keyValues.count(key)) { // Check if the key exists in the current section
175+
lines.push_back(key + " = " + iniData[currentSection].keyValues[key]); // Add the updated key-value pair to the vector
155176
} else {
156-
lines.push_back(line);
177+
lines.push_back(line); // Add the original line to the vector
157178
}
158179
} else {
159-
lines.push_back(line);
180+
lines.push_back(line); // Add the line to the vector
160181
}
161182
}
162-
inFile.close();
183+
inFile.close(); // Close the input file
163184

164-
std::ofstream outFile(filename);
165-
if (!outFile.is_open()) {
185+
std::ofstream outFile(filename); // Open the file for writing
186+
if (!outFile.is_open()) { // Check if the file is opened successfully
166187
std::cerr << "Failed to write " << filename << std::endl;
167188
return;
168189
}
169-
for (const auto& l : lines) outFile << l << "\n";
170-
outFile.close();
190+
for (const auto& l : lines) outFile << l << "\n"; // Write each line to the output file
191+
outFile.close(); // Close the output file
171192
}
172193

173194
void initExplanations() {
@@ -340,10 +361,10 @@ class IniEditor {
340361
for (size_t i = 0; i < sections.size(); ++i) {
341362
if (static_cast<int>(i) == dropdownHoverIndex) {
342363
SDL_Rect highlight = {10, y, 190, 20};
343-
SDL_SetRenderDrawColor(renderer, 200, 200, 200, 255);
364+
SDL_SetRenderDrawColor(renderer, 200, 200, 200, 255); // Highlight color
344365
SDL_RenderFillRect(renderer, &highlight);
345366
}
346-
renderText(sections[i], 15, y);
367+
renderText(sections[i], 15, y); // Render section name
347368
y += 20;
348369
}
349370
}
@@ -352,35 +373,35 @@ class IniEditor {
352373
int y = 50;
353374
if (iniData.count(currentSection)) { // Check if section exists
354375
for (const auto& [key, value] : iniData[currentSection].keyValues) {
355-
if (y + 20 - scrollOffset < 40 || y - scrollOffset > 400) {
376+
if (y + 20 - scrollOffset < 40 || y - scrollOffset > 400) { // Skip rendering if out of view
356377
y += 30;
357378
continue;
358379
}
359-
renderText(key, 10, y - scrollOffset);
380+
renderText(key, 10, y - scrollOffset); // Render key
360381
if (key == activeField) {
361382
SDL_Rect fieldRect = {150, y - scrollOffset, 300, 20};
362-
SDL_SetRenderDrawColor(renderer, 200, 200, 200, 255);
383+
SDL_SetRenderDrawColor(renderer, 200, 200, 200, 255); // Active field color
363384
SDL_RenderFillRect(renderer, &fieldRect);
364385
}
365-
renderText(value, 150, y - scrollOffset);
366-
if (explanations.count(key)) renderText("?", 120, y - scrollOffset);
386+
renderText(value, 150, y - scrollOffset); // Render value
387+
if (explanations.count(key)) renderText("?", 120, y - scrollOffset); // Render tooltip indicator
367388
y += 30;
368389
}
369390
}
370391

371392
// Render Save/Exit buttons
372393
SDL_Rect saveBtn = {10, 360, 55, 25};
373394
SDL_Rect exitBtn = {75, 360, 55, 25};
374-
SDL_SetRenderDrawColor(renderer, 200, 200, 200, 255);
395+
SDL_SetRenderDrawColor(renderer, 200, 200, 200, 255); // Button color
375396
SDL_RenderFillRect(renderer, &saveBtn);
376397
SDL_RenderFillRect(renderer, &exitBtn);
377-
renderText("Save", 20, 365);
378-
renderText("Exit", 90, 365);
398+
renderText("Save", 20, 365); // Render Save button text
399+
renderText("Exit", 90, 365); // Render Exit button text
379400

380401
// Render tooltip
381402
if (!tooltipKey.empty() && explanations.count(tooltipKey)) {
382403
SDL_Rect tooltipRect = {150, 50, 300, 100};
383-
SDL_SetRenderDrawColor(renderer, 240, 240, 200, 255);
404+
SDL_SetRenderDrawColor(renderer, 240, 240, 200, 255); // Tooltip background color
384405
SDL_RenderFillRect(renderer, &tooltipRect);
385406
std::string text = explanations[tooltipKey];
386407
int y = 55;
@@ -389,33 +410,33 @@ class IniEditor {
389410
size_t next = text.find('\n', pos);
390411
if (next == std::string::npos) next = text.length();
391412
std::string line = text.substr(pos, next - pos);
392-
renderText(line, 155, y);
413+
renderText(line, 155, y); // Render tooltip text line by line
393414
y += 20;
394415
pos = next + 1;
395416
}
396417
}
397418

398-
SDL_RenderPresent(renderer);
419+
SDL_RenderPresent(renderer); // Present the rendered frame
399420
}
400421

401422
void renderText(const std::string& text, int x, int y) {
402-
if (!font || text.empty()) return;
403-
SDL_Color color = {0, 0, 0, 255}; // Black
404-
SDL_Surface* surface = TTF_RenderText_Solid(font, text.c_str(), color);
423+
if (!font || text.empty()) return; // Check if font is loaded and text is not empty
424+
SDL_Color color = {0, 0, 0, 255}; // Black color for text
425+
SDL_Surface* surface = TTF_RenderText_Solid(font, text.c_str(), color); // Render text to surface
405426
if (!surface) {
406-
std::cerr << "TTF_RenderText_Solid failed: " << TTF_GetError() << std::endl;
427+
std::cerr << "TTF_RenderText_Solid failed: " << TTF_GetError() << std::endl; // Error handling
407428
return;
408429
}
409-
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
430+
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface); // Create texture from surface
410431
if (!texture) {
411-
std::cerr << "SDL_CreateTextureFromSurface failed: " << SDL_GetError() << std::endl;
412-
SDL_FreeSurface(surface);
432+
std::cerr << "SDL_CreateTextureFromSurface failed: " << SDL_GetError() << std::endl; // Error handling
433+
SDL_FreeSurface(surface); // Free surface if texture creation fails
413434
return;
414435
}
415-
SDL_Rect dst = {x, y, surface->w, surface->h};
416-
SDL_RenderCopy(renderer, texture, nullptr, &dst);
417-
SDL_FreeSurface(surface);
418-
SDL_DestroyTexture(texture);
436+
SDL_Rect dst = {x, y, surface->w, surface->h}; // Destination rectangle for rendering
437+
SDL_RenderCopy(renderer, texture, nullptr, &dst); // Copy texture to renderer
438+
SDL_FreeSurface(surface); // Free the surface
439+
SDL_DestroyTexture(texture); // Destroy the texture
419440
}
420441
};
421442

0 commit comments

Comments
 (0)