No description
cmake | ||
examples | ||
include/cigui | ||
src | ||
tests | ||
.gitignore | ||
CMakeLists.txt | ||
LICENSE | ||
README.md |
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: PascalCase (e.g.,
GridLayout.hpp
)
Classes and Types
- Class names: PascalCase (e.g.,
Button
,GridLayout
) - Type aliases/typedefs: lowercase (e.g.,
using view_ptr = std::shared_ptr<View>
) - Enum names: PascalCase
- Enum values: PascalCase/UPPERCASE (e.g.,
enum class Alignment { TopLeft, Center, BottomRight }
orenum class Direction { LEFT, UP, RIGHT, DOWN }
)
Functions and Variables
- API function names: camelCase (e.g.,
getPosition()
,setVisible()
) - Internal function names: lowercase (e.g.
render_view()
,get_visibility()
) - Variable names: camelCase (e.g.,
buttonText
,isVisible
) - Member variables: prefix with
m_
+ UpperCamelCase (e.g.,m_Position
,m_Size
) - Static variables: prefix with
s_
+ UpperCamelCase (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
// 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:
- Related header
- C++ standard library headers
- Third-party library headers (SFML)
- CIGUI headers
- Forward declare classes when possible to reduce dependencies
// 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:
- Constructors/Destructors
- Public methods
- Event callbacks
- Static methods
- Member variables
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
// 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
/**
* @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!
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
// 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
#include <cigui.hpp>
struct ContentView : public cig::View {
void body() {
cig::VStack(
cig::SystemIcon("globe.fill"),
cig::Text("Welcome to Cigui")
)
}
}
struct SettingsView : public cig::View {
void body() {
cig::Tabbed(
cig::Tab(
).tag("Tab 1"),
cig::Tab(
cig::VStack(
cig::Text("Other Tab")
)
)
);
}
}
struct MainApp : public cig::App {
void body() {
cig::WindowGroup()(
cig::ViewWindow(new ContentView()),
cig::SettingsWindow(new SettingsView())
)
}
}