Skip to content

Commit

Permalink
Merge pull request #380 from tannerhelland/toolbox-on-top - all-new t…
Browse files Browse the repository at this point in the history
…ool panel UX

Fixes #333 

This (giant) pull request brings the biggest overhaul to PhotoDemon's main toolbox since on-canvas tools were first added to the project many years ago.

Tool panels are now aligned at the top of PhotoDemon's canvas, like all other mainstream photo editors.  

The tool panel box itself has been shrunk vertically vs the old design, freeing up additional space for the image canvas itself.

Each tool panel exposes the most commonly used settings directly on the panel.  Advanced and/or esoteric settings are now accessibly via "flyout panels", which expand beneath the tool panel with a single click on the associated title-bar (or when a control in that group receives focus).  Here's an animation of the paintbrush tool's flyout panels, for example:

![capture-new-toolpanels](https://user-images.githubusercontent.com/1930029/144650858-520ab58a-08f3-42ab-bbdd-deb7f0c81a2d.png)

Flyout panels collapse automatically when you navigate away from them.  If you want to maintain persistent access to a panel, a "pin" button is provided on each - just click it to force that flyout panel to stay open, even when you interact with the canvas and/or menu items.  (Flyout panels will still close when you switch to a new tool or open a new panel, by necessity.)

All tool panels are now 100% navigable by keyboard.  Tab order has been manually verified for each panel, and *all* settings on *all* panels are now reachable without the mouse.

All tool panels now (finally!) support a minimum screen resolution of 1024 pixels.  This limitation may make them feel "sparse" at larger resolutions.  I have some ideas for resolving this (possibly by automatically moving esoteric settings out of flyout panels and into the toolbar itself if the screen is large enough - but this remains TODO pending further study).

As an added bonus, this branch includes a large set of in-progress work on PhotoDemon's selection tools, preparing them for multiple selections (so you can merge subsequent selections together).  This work is *not* complete, but I needed to merge it because selection tools have received a number of UI changes to prepare for this feature.  A bunch of other selection improvements are part of this branch, and once this tool panel work is complete, I can continue hacking away at multiple selection support.  (I mention this because a new "selection combine mode" UI is now available, but disabled.  Don't be alarmed by that!)

I have tested the new tool panel design on XP, Win 10, and Win 11.  Win 7 testing will be performed soon.  If you encounter weirdness on Vista or Win 8, please let me know as I no longer keep those VMs around for testing.
  • Loading branch information
tannerhelland authored Dec 3, 2021
2 parents ba7d9fa + 4080fbc commit 471070d
Show file tree
Hide file tree
Showing 83 changed files with 12,189 additions and 7,946 deletions.
435 changes: 227 additions & 208 deletions App/PhotoDemon/Languages/French.xml

Large diffs are not rendered by default.

435 changes: 227 additions & 208 deletions App/PhotoDemon/Languages/German.xml

Large diffs are not rendered by default.

425 changes: 222 additions & 203 deletions App/PhotoDemon/Languages/Indonesian.xml

Large diffs are not rendered by default.

433 changes: 226 additions & 207 deletions App/PhotoDemon/Languages/Italian.xml

Large diffs are not rendered by default.

425 changes: 222 additions & 203 deletions App/PhotoDemon/Languages/Macedonian.xml

Large diffs are not rendered by default.

347 changes: 183 additions & 164 deletions App/PhotoDemon/Languages/Master/MASTER.xml

Large diffs are not rendered by default.

433 changes: 226 additions & 207 deletions App/PhotoDemon/Languages/Polish.xml

Large diffs are not rendered by default.

433 changes: 226 additions & 207 deletions App/PhotoDemon/Languages/Simplified_Chinese.xml

Large diffs are not rendered by default.

433 changes: 226 additions & 207 deletions App/PhotoDemon/Languages/Spanish_(Mexico).xml

Large diffs are not rendered by default.

433 changes: 226 additions & 207 deletions App/PhotoDemon/Languages/Spanish_(Spain).xml

Large diffs are not rendered by default.

425 changes: 222 additions & 203 deletions App/PhotoDemon/Languages/Traditional_Chinese.xml

Large diffs are not rendered by default.

347 changes: 183 additions & 164 deletions App/PhotoDemon/Languages/Turkish.xml

Large diffs are not rendered by default.

433 changes: 226 additions & 207 deletions App/PhotoDemon/Languages/Vlaams.xml

Large diffs are not rendered by default.

Binary file modified App/PhotoDemon/Themes/Core_Icons.pdrc
Binary file not shown.
4 changes: 2 additions & 2 deletions Classes/pd2DBrush.cls
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ Friend Function SetBrushTextureTransform(ByRef srcTransform As pd2DTransform) As

'Warn the caller that setting a transform on a null-brush isn't technically allowed,
' but attempt to work around that by creating the brush for them anyway
If (m_BrushHandle <> 0) Then
If (m_BrushHandle = 0) Then
InternalError "SetBrushTextureTransform", "Brush must exist before setting transform; creating now..."
Me.CreateBrush
End If
Expand Down Expand Up @@ -523,6 +523,7 @@ Friend Function CreateBrush() As Boolean
Case P2_BM_Solid
GetMem4 VarPtr(m_BrushRGBA), tmpLong
CreateBrush = (GdipCreateSolidFill(tmpLong, m_BrushHandle) = GP_OK)
If CreateBrush Then CreateBrush = (m_BrushHandle <> 0)

'Pattern fill
Case P2_BM_Pattern
Expand Down Expand Up @@ -557,7 +558,6 @@ Friend Function CreateBrush() As Boolean
End Select

'When debug mode is active, all object creations are reported back to the master Drawing2D module
If CreateBrush Then CreateBrush = (m_BrushHandle <> 0)
If (CreateBrush And PD2D_DEBUG_MODE) Then Drawing2D.DEBUG_NotifyBrushCountChange True

End Function
Expand Down
13 changes: 7 additions & 6 deletions Classes/pdCaption.cls
Original file line number Diff line number Diff line change
Expand Up @@ -372,9 +372,10 @@ Friend Sub DrawCaption(ByVal dstDC As Long, Optional ByVal dstX As Long = 0, Opt

End Sub

'When all font and caption settings are ready, use this to actually render the caption onto a target DC. Clipping to the
' destination area will occur automatically, with ellipses applied according to the useEllipses parameter. Note that you
' can also request to use the original font size, instead of the auto-fit size.
'When all font and caption settings are ready, use this to actually render the caption onto a target DC.
' Clipping to the destination area will occur automatically, with ellipses applied according to the
' useEllipses parameter. Note that you can also request to use the original font size, instead of the
' auto-fit size.
Friend Sub DrawCaption_Clipped(ByVal dstDC As Long, ByVal dstX As Long, ByVal dstY As Long, ByVal dstWidth As Long, ByVal dstHeight As Long, Optional ByVal customColor As Long = -1, Optional ByVal useEllipses As Boolean = False, Optional ByVal useOriginalFontSize As Boolean = False, Optional ByVal centerVertically As Boolean = False)

'Make sure we can fit the current caption inside the control, when using the selected font size. (If we can't,
Expand Down Expand Up @@ -403,9 +404,9 @@ Friend Sub DrawCaption_Clipped(ByVal dstDC As Long, ByVal dstX As Long, ByVal ds

tmpFont.AttachToDC dstDC

'NOTE: pdFont.SetTextAlignment does not actually set text alignment as a property inside the target DC. Instead, it uses
' DrawText flags to enforce alignment. This leaves the target DC untouched, so previously set text flags won't be
' modified by calls to pdFont, by design.
'NOTE: pdFont.SetTextAlignment does not actually set text alignment as a property inside the target DC.
' Instead, it uses DrawText flags to enforce alignment. This leaves the target DC untouched,
' so previously set text flags won't be modified by calls to pdFont, by design.
tmpFont.SetTextAlignment m_Alignment

If m_WordWrapAllowed Then
Expand Down
4 changes: 2 additions & 2 deletions Classes/pdDIB.cls
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ Friend Sub EraseDIB(Optional ByVal alsoReleaseDC As Boolean = False)
GDI.FreeMemoryDC m_dibDC
m_dibDC = 0
End If

'Reset all associated DIB section variables
m_dibHandleOriginal = 0
m_dibHandle = 0
Expand All @@ -983,7 +983,7 @@ Friend Sub EraseDIB(Optional ByVal alsoReleaseDC As Boolean = False)
m_SizeSuspended = 0
m_SizeUnsuspended = 0
Erase m_SuspensionBuffer
m_IsSuspended = 0
m_IsSuspended = False

'Finally, release the memory-mapped file backing the DIB, if one exists
If (Not m_FileMM Is Nothing) Then m_FileMM.CloseFile
Expand Down
4 changes: 2 additions & 2 deletions Classes/pdDictionary.cls
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,8 @@ Friend Function DoesKeyExist(ByVal entryKey As String) As Boolean
DoesKeyExist = (GetIndexOfEntry(entryKey) >= 0)
End Function

'This helper function is used to retrieve dictionary indices, using the requested key. If a key cannot be found,
' this function will return -1.
'This helper function is used to retrieve dictionary indices, using the requested key.
' If a key cannot be found, this function will return -1.
Private Function GetIndexOfEntry(ByRef entryKey As String) As Long

'Search the dictionary array, looking for a match
Expand Down
17 changes: 9 additions & 8 deletions Classes/pdEditBoxW.cls
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,6 @@ Private Const WM_COMMAND As Long = &H111
Private Const WM_CTLCOLOREDIT As Long = &H133
Private Const WM_CTLCOLORSTATIC As Long = &H138
Private Const WM_DESTROY As Long = &H2

Private Const EN_UPDATE As Long = &H400
Private Const EM_GETSEL As Long = &HB0
Private Const EM_SETSEL As Long = &HB1
Expand Down Expand Up @@ -813,6 +812,7 @@ Private Function HandleEditBoxMsgs(ByVal hWnd As Long, ByVal uiMsg As Long, ByVa
'Raise a matching notification
If (Not m_HasFocus) Then
m_HasFocus = True
UserControls.PDControlReceivedFocus hWnd
RaiseEvent GotFocusAPI
End If

Expand All @@ -829,6 +829,7 @@ Private Function HandleEditBoxMsgs(ByVal hWnd As Long, ByVal uiMsg As Long, ByVa
'Raise a matching notification
If m_HasFocus Then
m_HasFocus = False
UserControls.PDControlLostFocus hWnd
RaiseEvent LostFocusAPI
End If

Expand All @@ -842,7 +843,7 @@ Private Function HandleEditBoxMsgs(ByVal hWnd As Long, ByVal uiMsg As Long, ByVa
HandleEditBoxMsgs = 0
msgEaten = True
End If

'Failsafe window destruction check
ElseIf (uiMsg = WM_NCDESTROY) Then

Expand All @@ -861,7 +862,7 @@ Private Function HandleParentMsgs(ByVal hWnd As Long, ByVal uiMsg As Long, ByVal
'The parent receives this message for all kinds of things; we subclass it to track when the edit box's contents have changed.
' (And when we don't handle the message, it is *very important* that we forward it correctly!
If (uiMsg = WM_COMMAND) Then

'Make sure the command is relative to *our* edit box, and not another one
If (lParam = m_EditBoxHwnd) Then

Expand Down Expand Up @@ -985,12 +986,12 @@ Private Function HandleKeyProc(ByVal nCode As Long, ByVal wParam As Long, ByVal
msgEaten = True
End If

'If the edit box is *not* multiline, check for tab presses and raise them manually
If (wParam = VK_TAB) And (Not m_Multiline) Then

'Check for tab presses and raise them manually. (Note that this step may need to
' be skipped in multiline edit boxes - for now, PD assumes TAB is always a navigation
' command, but perhaps we'll want to use a property to toggle this in the future?)
If (wParam = VK_TAB) Then
RaiseEvent KeyPress(retShiftConstants, wParam, msgEaten)
msgEaten = True

End If

End If
Expand All @@ -1005,7 +1006,7 @@ Friend Function EditBoxKeyboardProc(ByVal nCode As Long, ByVal wParam As Long, B

'If we've shut down our internal hook handling code, ignore this event completely if.
If (m_HookID <> 0) Then

Dim msgEaten As Boolean: msgEaten = False

'MSDN states that negative codes must be passed to the next hook, without processing
Expand Down
Loading

0 comments on commit 471070d

Please sign in to comment.