PCSX2 Documentation/WxWidgets Coding Strategies: Difference between revisions

no edit summary
No edit summary
No edit summary
Line 3: Line 3:
This means that you should, whenever possible, use the following classes instead of other common alternatives:
This means that you should, whenever possible, use the following classes instead of other common alternatives:


* `wxString` instead of `std::string` or `std::wstring`.
* <code>wxString</code> instead of <code>std::string</code> or <code>std::wstring</code>.
* `wxChar` instead of `TCHAR`
* <code>wxChar</code> instead of <code>TCHAR</code>
* `wxString::Format` and `wxString::Printf` (available also via the shortcut `wxsFormat`) instead of `sprintf, snprintf`, or `ssprintf`.
* <code>wxString::Format</code> and <code>wxString::Print</code> (available also via the shortcut <code>wxsFormat</code>) instead of <code>sprintf</code>, <code>snprintf</code>, or <code>ssprintf</code>.
* `wxDateTime` instead of POSIX ctime or Windows date functions.
* <code>wxDateTime</code> instead of POSIX ctime or Windows date functions.
* `wxFile` instead of `FILE` or Windows `OpenFile` (yes `wxFile` supports files over 4gb).
* <code>wxFile</code> instead of <code>FILE</code> or Windows <code>OpenFile</code> (yes <code>wxFile</code> supports files over 4gb).
* Use the `wx*` alternatives for any ANSI C library function, such as `wxGetCwd, wxStrlen`, etc. (as wx should provide platform independent versions of almost everything).
* Use the <code>wx*</code> alternatives for any ANSI C library function, such as <code>wxGetCwd</code>, <code>wxStrlen</code>, etc. (as wx should provide platform independent versions of almost everything).


'''There are some exceptions to this last rule:'''
'''There are some exceptions to this last rule:'''


* We use our own internal `pxThread` class instead of `wxThread`, mostly due to the w32pthreads library being much more robust and efficient than wx's cross-platform threading. (some `wxThread` static functions are still are of use, however, such as `wxThread::IsMain()`).
* We use our own internal <code>pxThread</code> class instead of <code>wxThread</code>, mostly due to the w32pthreads library being much more robust and efficient than wx's cross-platform threading. (some <code>wxThread</code> static functions are still are of use, however, such as <code>wxThread::IsMain()</code>).
* wxWidgets logging facilities are poorly designed and not at all suited to PCSX2 needs. We have our own `Console` and `SourceLog` systems instead. `Console` uses the `IConsoleWriter` interface internally and supports both Unicode and console output redirection. `SourceLog` is intended for high volume logging (trace logs of PS2 execution) and is optimized to write untranslated ASCII text to logfile.
* wxWidgets logging facilities are poorly designed and not at all suited to PCSX2 needs. We have our own <code>Console</code> and <code>SourceLog</code> systems instead. <code>Console</code> uses the <code>IConsoleWriter</code> interface internally and supports both Unicode and console output redirection. <code>SourceLog</code> is intended for high volume logging (trace logs of PS2 execution) and is optimized to write untranslated ASCII text to logfile.
* Console logging and devel/debug messages do not need to be translated, and do not need to use `wxString` to maintain proper cross-platform unicode support. All console logging functions can use either plain `ASCII-Z (char*)` string and functions or `wxChar*`; depending on whichever is more convenient at the time.
* Console logging and devel/debug messages do not need to be translated, and do not need to use <code>wxString</code> to maintain proper cross-platform unicode support. All console logging functions can use either plain <code>ASCII-Z (char*)</code> string and functions or <code>wxChar*</code>; depending on whichever is more convenient at the time.
* Trace logging is meant to be used for ASCII/UTF8 text only, and has no support for `wxChar`or `wxString.` This is done largly for performance reasons.
* Trace logging is meant to be used for ASCII/UTF8 text only, and has no support for <code>wxChar</code>or <code>wxString.</code> This is done largly for performance reasons.
* Forego the use of `_T()` or `wxT()`, in favor of the now-standard `L''` for denoting unicode strings. wx2.8 stores all strings in wchar_t format internally on all supported platforms, so `L""` is sufficient for full cross platform support. In the event we upgrade to wx3.0 this won't be a 'perfectly' optimal scenario in Unix builds, since wx3.0 on Linux will store strings in UTF8 format internally anyway (but provides automatic conversions, so it will still compile and run without error). The overhead is in non-critical scenarios where I'm willing to sacrifice some cpu load in favor of cleaner code.
* Forego the use of <code>_T()</code> or <code>wxT()</code>, in favor of the now-standard <code>L''</code> for denoting unicode strings. wx2.8 stores all strings in wchar_t format internally on all supported platforms, so <code>L""</code> is sufficient for full cross platform support. In the event we upgrade to wx3.0 this won't be a 'perfectly' optimal scenario in Unix builds, since wx3.0 on Linux will store strings in UTF8 format internally anyway (but provides automatic conversions, so it will still compile and run without error). The overhead is in non-critical scenarios where I'm willing to sacrifice some cpu load in favor of cleaner code.


(any others...?)
(any others...?)


## Utilizing GUI Components
==Utilizing GUI Components==


PCSX2 opts for the "hand-made" approach to dialog box design, rather than using form designers and resource files. This reduces the number of external library and application dependencies needed to build or contribute to PCSX2, and is often an ideal approach to GUI design via sizers and spacers (which is the preferred layout system in wxwidgets). Make sure to always create a new dialog/UI as one or more **Panels**, rather than adding controls directly to a Dialog window. Panels are much more flexable devices and they allow us the option of adding dockable panel features to PCSX2's UI at a later date. Panels also make re-arranging the window contents of the current static GUI a lot easier (if necessary).
PCSX2 opts for the "hand-made" approach to dialog box design, rather than using form designers and resource files. This reduces the number of external library and application dependencies needed to build or contribute to PCSX2, and is often an ideal approach to GUI design via sizers and spacers (which is the preferred layout system in wxwidgets). Make sure to always create a new dialog/UI as one or more **Panels**, rather than adding controls directly to a Dialog window. Panels are much more flexable devices and they allow us the option of adding dockable panel features to PCSX2's UI at a later date. Panels also make re-arranging the window contents of the current static GUI a lot easier (if necessary).
Line 30: Line 30:
... If using native wxWidgets controls with tooltips, use `pxSetToolTip` instead of the control's built in `SetToolTip.` This ensures proper tooltip length on win32 platforms. Custom px-based controls override the SetToolTip internally to do word wrapping as needed, so you can use their built-in `SetToolTip` methods.
... If using native wxWidgets controls with tooltips, use `pxSetToolTip` instead of the control's built in `SetToolTip.` This ensures proper tooltip length on win32 platforms. Custom px-based controls override the SetToolTip internally to do word wrapping as needed, so you can use their built-in `SetToolTip` methods.


## wxPanelWithHelpers
==wxPanelWithHelpers==


The primary purpose of wxPanelWithHelpers is to compensate for wxWidgets inability to resize panels and dialogs with static text word wrapping in mind. (****see below for details on why) So instead we specify the ideal or maximum width of the dialog to wxPanelWithHelpers, and then use our own `pxStaticText` widget to add wrappable text to the panel, which will be wrapped to fit to the ideal width of the panel. Child panels of the wxPanelWithHelpers automatically inherit the maximum width from that panel, and automatically guesstimate their own width based on typical borders offrames and static group boxes.
The primary purpose of wxPanelWithHelpers is to compensate for wxWidgets inability to resize panels and dialogs with static text word wrapping in mind. (****see below for details on why) So instead we specify the ideal or maximum width of the dialog to wxPanelWithHelpers, and then use our own `pxStaticText` widget to add wrappable text to the panel, which will be wrapped to fit to the ideal width of the panel. Child panels of the wxPanelWithHelpers automatically inherit the maximum width from that panel, and automatically guesstimate their own width based on typical borders offrames and static group boxes.
Line 40: Line 40:
TODO: In the future it might work best to have the ideal/maximum width be a function of the user's dialog font size, to allow for the dialog to expand to accomodte the real-estire of larger fonts.
TODO: In the future it might work best to have the ideal/maximum width be a function of the user's dialog font size, to allow for the dialog to expand to accomodte the real-estire of larger fonts.


## Maintain 'Emulation Core' and 'User Interface' Separation
==Maintain 'Emulation Core' and 'User Interface' Separation==


As of the writing of this doc, this topic is still a work-in-progress on the wx branch, meaning that there are still a few spots in the Emulation Core code that make direct references to the gui. These spots willhopefully get resolved in the near future.
As of the writing of this doc, this topic is still a work-in-progress on the wx branch, meaning that there are still a few spots in the Emulation Core code that make direct references to the gui. These spots willhopefully get resolved in the near future.
Line 48: Line 48:
Currently however there is no distinct separation between the emulation core and the wx-based GUI, since there are still several intertwined dependencies that still need to be dealt with in a nice manner.
Currently however there is no distinct separation between the emulation core and the wx-based GUI, since there are still several intertwined dependencies that still need to be dealt with in a nice manner.


## Core/VM and UI Threading
==Core/VM and UI Threading==


The emulator core and UI are now running on independent threads, which means the UI cannot safely change the emulator's settings whenever it feels like it. This will result in nasty bugs caused by obscure threading race conditions. To solve this, most Core and UI settings have been separated into two structures, `Pcsx2Config` (for core emu options), and `AppConfig` (wx-UI options). `AppConfig` contains its own copy of `Pcsx2Config` since, as a UI, it needs to maintain both its own options and the options it uses to invoke emulation. The wxUI's instance of AppConfig is called `g_Conf`. The emu core uses its own local copy of settings, called `EmuConfig`, (defined as `extern const Pcsx2Config EmuConfig`).
The emulator core and UI are now running on independent threads, which means the UI cannot safely change the emulator's settings whenever it feels like it. This will result in nasty bugs caused by obscure threading race conditions. To solve this, most Core and UI settings have been separated into two structures, `Pcsx2Config` (for core emu options), and `AppConfig` (wx-UI options). `AppConfig` contains its own copy of `Pcsx2Config` since, as a UI, it needs to maintain both its own options and the options it uses to invoke emulation. The wxUI's instance of AppConfig is called `g_Conf`. The emu core uses its own local copy of settings, called `EmuConfig`, (defined as `extern const Pcsx2Config EmuConfig`).
Line 54: Line 54:
There are several other guidelines you need to be aware of before attempting to modify PCSX2 settings. Please read Settings between UI and Core Threads for more details on how to use the two-conf system.
There are several other guidelines you need to be aware of before attempting to modify PCSX2 settings. Please read Settings between UI and Core Threads for more details on how to use the two-conf system.


## Be Careful when Sending Events to Other Windows
==Be Careful when Sending Events to Other Windows==


_TODO : obsolete. Replace with a link to documented use of th new pxEvent system._
_TODO : obsolete. Replace with a link to documented use of th new pxEvent system._
Line 86: Line 86:
... So the moral of the story is: Use `GetEventHandler()` when possible (basically anything except the `wxApp` object), and use `AddPendingEvent()` unless you need a return code _and_ know you're on the main GUI thread.
... So the moral of the story is: Use `GetEventHandler()` when possible (basically anything except the `wxApp` object), and use `AddPendingEvent()` unless you need a return code _and_ know you're on the main GUI thread.


## Guidelines when Using Windows/Linux Specific Code
==Guidelines when Using Windows/Linux Specific Code==


The simple rule is to not use any windows or linux specific code unless absolutely necessary. Most of the time _wxWidgets_ provisions us with cross-platform alternatives for most tasks, so always make sure to check the wx documentation first. But, of course, there are still cases of advanced coding that wx doesn't cover, and these will need platform specific implementations. For example, there is no direct Linux equivalent of Windows Structured Exception Handling (SEH), and PCSX2 code that uses SEH must either be coded to use Linux signals (if possible) or `#ifdef`'d out under Linux.
The simple rule is to not use any windows or linux specific code unless absolutely necessary. Most of the time _wxWidgets_ provisions us with cross-platform alternatives for most tasks, so always make sure to check the wx documentation first. But, of course, there are still cases of advanced coding that wx doesn't cover, and these will need platform specific implementations. For example, there is no direct Linux equivalent of Windows Structured Exception Handling (SEH), and PCSX2 code that uses SEH must either be coded to use Linux signals (if possible) or `#ifdef`'d out under Linux.


### There are two ways to handle separate Windows and Linux implementations
===There are two ways to handle separate Windows and Linux implementations===


  * Create two separate files, one under /Windows and one under /Linux, that each implement a function as according to the platform needs. _(preferred)_
* Create two separate files, one under /Windows and one under /Linux, that each implement a function as according to the platform needs. _(preferred)_
  * Use inline #ifdefs to separate behavior. _(useful for very simple/short differences)_
* Use inline #ifdefs to separate behavior. _(useful for very simple/short differences)_


As noted, it's generally preferred to create implementations in platform specific files over using `#ifdef`. This helps keep code much cleaner and saner, and is more friendly toward code editors/IDEs as well (most editors handle `#ifdef` poorly, either failing to gray out the unused defines, or by enforcing an ugly tabbing layout that is only suited to function-level codeblock removal). When using platform specific files it's usually preferred to have each filename assigned the platform's tag. Example:
As noted, it's generally preferred to create implementations in platform specific files over using `#ifdef`. This helps keep code much cleaner and saner, and is more friendly toward code editors/IDEs as well (most editors handle `#ifdef` poorly, either failing to gray out the unused defines, or by enforcing an ugly tabbing layout that is only suited to function-level codeblock removal). When using platform specific files it's usually preferred to have each filename assigned the platform's tag. Example:
ninja
782

edits