Add a standalone style guide document

Moved the CIGUI style guide from `README.md` to a dedicated `StyleGuide.md` file for better organization. This improves readability and ensures the main README remains focused on project goals and usage.
This commit is contained in:
noffie 2025-04-20 18:48:25 +02:00
parent 3679beaa4e
commit b12e608567
2 changed files with 240 additions and 244 deletions

244
README.md
View file

@ -1,249 +1,5 @@
# cigui
## CIGUI Style Guide
This document outlines the coding standards and best practices for the CIGUI library. Following these guidelines ensures consistency across the project and makes the codebase more maintainable.
### General Principles
- **Clarity over cleverness**: Write code that's easy to understand, not code that's clever.
- **Consistency**: Follow established patterns within the codebase.
- **Documentation**: Document public APIs thoroughly.
- **Testability**: Write code that can be easily tested.
### Naming Conventions
#### Files
- Header files: `.hpp` for C++ headers, `.h` for C-compatible headers
- Implementation files: `.cpp`
- Template implementation files: `.inl`
- File names: lowercase with underscores (e.g., `grid_layout.hpp`)
#### Classes and Types
- Class names: PascalCase (e.g., `Button`, `GridLayout`)
- Type aliases/typedefs: PascalCase (e.g., `using WidgetPtr = std::shared_ptr<View>`)
- Enum names: PascalCase
- Enum values: PascalCase (e.g., `enum class Alignment { TopLeft, Center, BottomRight }`)
#### Functions and Variables
- Function names: camelCase (e.g., `getPosition()`, `setVisible()`)
- Variable names: camelCase (e.g., `buttonText`, `isVisible`)
- Member variables: prefix with `m_` (e.g., `m_position`, `m_size`)
- Static variables: prefix with `s_` (e.g., `s_defaultFont`)
- Constants and macros: ALL_CAPS with underscores (e.g., `MAX_WIDGETS`, `CIGUI_API`)
### Code Structure
#### Namespaces
- All library code should be inside the `cig` namespace
- Avoid deeply nested namespaces
- Do not use `using namespace` in headers
```cpp
// Good
namespace cig {
class Button : public View {
// ...
};
}
// Bad
using namespace sf; // Don't do this in headers
```
#### Headers
- Always use include guards with project-specific prefix
- Order includes as follows:
1. Related header
2. C++ standard library headers
3. Third-party library headers (SFML)
4. CIGUI headers
- Forward declare classes when possible to reduce dependencies
```cpp
// Example of a good header structure
#pragma once
#include <cigui/config.h>
#include <string>
#include <vector>
#include <SFML/Graphics/Drawable.hpp>
#include <cigui/utils/rect.hpp>
namespace cig {
class View; // Forward declaration
class CIGUI_API Container {
// Implementation
};
} // namespace cig
```
#### Classes
- Separate public, protected, and private sections
- Order within sections:
1. Constructors/Destructors
2. Public methods
3. Event callbacks
4. Static methods
5. Member variables
```cpp
class Button : public View {
public:
// Constructors/Destructors
Button();
explicit Button(const std::string& text);
~Button() override;
// Methods
void setText(const std::string& text);
const std::string& getText() const;
// Event dispatcher
EventDispatcher<MouseEvent> onClicked;
protected:
// Protected methods
void updateAppearance();
private:
// Private methods
void initializeGraphics();
// Member variables
std::string m_text;
sf::RectangleShape m_background;
bool m_isHovered;
};
```
### Templates
- Template implementation should be in `.inl` files
- Use explicit instantiation for common types in DLLs
- Document template parameters
```cpp
// In .hpp file
template<typename T>
class Container {
// ...
};
// Include the implementation
#include <cigui/widgets/container.inl>
// In .inl file
template<typename T>
Container<T>::Container() {
// ...
}
// In .cpp file for explicit instantiation
template class Container<int>;
template class Container<std::string>;
```
### C++ Features
- **C++ Standard**: Use C++20 features where appropriate
- **Smart Pointers**: Use `std::unique_ptr` for exclusive ownership, `std::shared_ptr` for shared ownership
- **Auto**: Use `auto` when the type is obvious or when using iterators
- **Range-based for loops**: Prefer over traditional for loops
- **Lambdas**: Use for short callbacks and event handlers
- **Move Semantics**: Support move operations where appropriate
### Comments and Documentation
- Use Doxygen-style comments for public APIs
- Comment complex algorithms and non-obvious code
- Avoid redundant comments that just repeat the code
```cpp
/**
* @brief Creates a button with the specified label text
*
* @param text The text to display on the button
* @param size The size of the button (default: 100x30)
*/
Button(const std::string& text, const sf::Vector2f& size = {100.f, 30.f});
```
### Error Handling
- Use exceptions for exceptional cases only
- Validate input parameters and handle edge cases
- Document error conditions in function comments
### Memory Management
- Prefer automatic memory management with smart pointers
- Explicitly define ownership models in documentation
- Design with RAII principles (Resource Acquisition Is Initialization)
### DLL/Shared Library Considerations
- Use `CIGUI_API` macro for all classes and non-inline functions
- Use `CIGUI_TEMPLATE_API` for template classes
- Handle template instantiation properly (see Templates section)
### SFML Integration
- Wrap SFML types when extending functionality
- Use SFML conventions for graphics-related code
- Don't expose SFML implementation details in public APIs when avoidable
### Testing
- Write unit tests for core functionality
- Test edge cases and error conditions
- Create interactive examples for UI components
### Formatting
- Indentation: 4 spaces (no tabs)
- Line length: 100 characters maximum
- Braces: Open brace on same line, close brace on new line
- Space after keywords (if, for, while)
- No space after function names
- Place * and & with the type, not the variable name
```cpp
// Good formatting example
if (condition) {
doSomething();
} else {
doSomethingElse();
}
void setPosition(const sf::Vector2f& position) {
m_position = position;
}
```
### Best Practices
- Prefer composition over inheritance
- Design interfaces that are hard to use incorrectly
- Follow the Rule of Five/Zero for class design
- Make data members private and provide accessors when needed
- Consider performance implications in UI code (avoid work in draw methods)
---
This style guide is a living document and may evolve as the project grows. When in doubt, maintain consistency with the existing codebase.
---
## Goal
```cpp

240
StyleGuide.md Normal file
View file

@ -0,0 +1,240 @@
## CIGUI Style Guide
This document outlines the coding standards and best practices for the CIGUI library. Following these guidelines ensures consistency across the project and makes the codebase more maintainable.
### General Principles
- **Clarity over cleverness**: Write code that's easy to understand, not code that's clever.
- **Consistency**: Follow established patterns within the codebase.
- **Documentation**: Document public APIs thoroughly.
- **Testability**: Write code that can be easily tested.
### Naming Conventions
#### Files
- Header files: `.hpp` for C++ headers, `.h` for C-compatible headers
- Implementation files: `.cpp`
- Template implementation files: `.inl`
- File names: lowercase with underscores (e.g., `grid_layout.hpp`)
#### Classes and Types
- Class names: PascalCase (e.g., `Button`, `GridLayout`)
- Type aliases/typedefs: PascalCase (e.g., `using WidgetPtr = std::shared_ptr<View>`)
- Enum names: PascalCase
- Enum values: PascalCase (e.g., `enum class Alignment { TopLeft, Center, BottomRight }`)
#### Functions and Variables
- Function names: camelCase (e.g., `getPosition()`, `setVisible()`)
- Variable names: camelCase (e.g., `buttonText`, `isVisible`)
- Member variables: prefix with `m_` (e.g., `m_position`, `m_size`)
- Static variables: prefix with `s_` (e.g., `s_defaultFont`)
- Constants and macros: ALL_CAPS with underscores (e.g., `MAX_WIDGETS`, `CIGUI_API`)
### Code Structure
#### Namespaces
- All library code should be inside the `cig` namespace
- Avoid deeply nested namespaces
- Do not use `using namespace` in headers
```cpp
// Good
namespace cig {
class Button : public View {
// ...
};
}
// Bad
using namespace sf; // Don't do this in headers
```
#### Headers
- Always use `#pragma once`
- Order includes as follows:
1. Related header
2. C++ standard library headers
3. Third-party library headers (SFML)
4. CIGUI headers
- Forward declare classes when possible to reduce dependencies
```cpp
// Example of a good header structure
#pragma once
#include <cigui/config.h>
#include <string>
#include <vector>
#include <SFML/Graphics/Drawable.hpp>
#include <cigui/utils/rect.hpp>
namespace cig {
class View; // Forward declaration
class CIGUI_API Container {
// Implementation
};
} // namespace cig
```
#### Classes
- Separate public, protected, and private sections
- Order within sections:
1. Constructors/Destructors
2. Public methods
3. Event callbacks
4. Static methods
5. Member variables
```cpp
class Button : public View {
public:
// Constructors/Destructors
Button();
explicit Button(const std::string& text);
~Button() override;
// Methods
void setText(const std::string& text);
const std::string& getText() const;
// Event dispatcher
EventDispatcher<MouseEvent> onClicked;
protected:
// Protected methods
void updateAppearance();
private:
// Private methods
void initializeGraphics();
// Member variables
std::string m_text;
sf::RectangleShape m_background;
bool m_isHovered;
};
```
### Templates
- Template implementation should be in `.inl` files
- Use explicit instantiation for common types in DLLs
- Document template parameters
```cpp
// In .hpp file
template<typename T>
class Container {
// ...
};
// Include the implementation
#include <cigui/widgets/container.inl>
// In .inl file
template<typename T>
Container<T>::Container() {
// ...
}
// In .cpp file for explicit instantiation
template class Container<int>;
template class Container<std::string>;
```
### C++ Features
- **C++ Standard**: Use C++20 features where appropriate
- **Smart Pointers**: Use `std::unique_ptr` for exclusive ownership, `std::shared_ptr` for shared ownership
- **Auto**: Use `auto` when the type is obvious or when using iterators
- **Range-based for loops**: Prefer over traditional for loops
- **Lambdas**: Use for short callbacks and event handlers
- **Move Semantics**: Support move operations where appropriate
### Comments and Documentation
- Use Doxygen-style comments for public APIs
- Comment complex algorithms and non-obvious code
- Avoid redundant comments that just repeat the code
```cpp
/**
* @brief Creates a button with the specified label text
*
* @param text The text to display on the button
* @param size The size of the button (default: 100x30)
*/
Button(const std::string& text, const sf::Vector2f& size = {100.f, 30.f});
```
### Error Handling
- Use exceptions for exceptional cases only
- Validate input parameters and handle edge cases
- Document error conditions in function comments
### Memory Management
- Prefer automatic memory management with smart pointers
- Explicitly define ownership models in documentation
- Design with RAII principles (Resource Acquisition Is Initialization)
### DLL/Shared Library Considerations
**TODO:** Think about this and add more details
### SFML Integration
- Wrap SFML types when extending functionality
- Use SFML conventions for graphics-related code
- Don't expose SFML implementation details in public APIs when avoidable
### Testing
- Write unit tests for core functionality
- Test edge cases and error conditions
- Create interactive examples for UI components
### Formatting
- Indentation: 4 spaces (no tabs)
- Line length: 100 characters maximum
- Braces: Open brace on same line, close brace on new line
- Space after keywords (if, for, while)
- No space after function names
- Place * and & with the type, not the variable name
```cpp
// Good formatting example
if (condition) {
doSomething();
} else {
doSomethingElse();
}
void setPosition(const sf::Vector2f& position) {
m_position = position;
}
```
### Best Practices
- Prefer composition over inheritance
- Design interfaces that are hard to use incorrectly
- Follow the Rule of Five/Zero for class design
- Make data members private and provide accessors when needed
- Consider performance implications in UI code (avoid work in draw methods)
---
This style guide is a living document and may evolve as the project grows. When in doubt, maintain consistency with the existing codebase.
---