Skip to content

Commit

Permalink
[#59] TrackEditor (Part 1: Drawing time and pitch under cursor)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomas-nestorovic committed Nov 28, 2020
1 parent 6ee35d8 commit 2626649
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 6 deletions.
3 changes: 2 additions & 1 deletion Main/res/resource.rc
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,8 @@ BEGIN
MENUITEM "Zoom out\t�", ID_ZOOM_OUT
MENUITEM "Zoom to fit\tCtrl+0", ID_ZOOM_FIT
MENUITEM SEPARATOR
MENUITEM "Show cursor time", ID_TIME
MENUITEM "Show time spacing", ID_GAP
MENUITEM "Show inspection", ID_RECOGNIZE
MENUITEM SEPARATOR
MENUITEM "Close\tEsc", IDCANCEL
Expand Down Expand Up @@ -1612,7 +1614,6 @@ END

IDR_TRACK_EDITOR DIALOG DISCARDABLE 0, 0, 442, 149
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION
CAPTION ""
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,332,128,50,14,NOT WS_VISIBLE | WS_DISABLED
Expand Down
1 change: 1 addition & 0 deletions Main/src/Image.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@


void SetCurrentTime(TLogTime logTime);
void TruncateCurrentTime();
TLogTime GetIndexTime(BYTE index) const;
TLogTime GetTotalTime() const;
TLogTime ReadTime();
Expand Down
105 changes: 101 additions & 4 deletions Main/src/Image_TrackEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,31 @@
#define TIME_HEIGHT 30
#define IW_HEIGHT (TIME_HEIGHT+10)
#define INDEX_HEIGHT 60
#define LINE_EXTENSION 5
#define SPACING_HEIGHT (IW_HEIGHT+LINE_EXTENSION)

class CTrackEditor sealed:public Utils::CRideDialog{
const CImage::CTrackReader &tr;
const LPCTSTR caption;
CMainWindow::CDynMenu menu;
PLogTime iwEndTimes;
HANDLE hAutoscrollTimer;

enum TCursorFeatures:BYTE{
TIME =1,
SPACING =2,
DEFAULT = TIME//|SPACING
};

class CTimeEditor sealed:public CScrollView{
Utils::CTimeline timeline;
CImage::CTrackReader tr;
TLogTime scrollTime;
PCLogTime iwEndTimes; // inspection window end Times (aka. at which Time they end; the end determines the beginning of the immediately next inspection window)
TLogTime draggedTime; // Time at which left mouse button has been pressed
TLogTime cursorTime; // Time over which the cursor hovers
BYTE cursorFeatures; // OR-ed TCursorFeatures values
bool cursorFeaturesShown; // internally used for painting
struct TTrackPainter sealed{
const CBackgroundAction action;
struct{
Expand Down Expand Up @@ -133,6 +144,53 @@
);
}

void PaintCursorFeaturesInverted(bool show){
// paints CursorTime by inverting pixels; painting twice the same CursorTime shows nothing
if ((show^cursorFeaturesShown)!=0 && cursorFeatures!=0){
CClientDC dc(this);
PrepareDC(&dc);
::SetROP2( dc, R2_NOT );
const auto &font=Utils::CRideFont::Std;
const HDC dcMem=::CreateCompatibleDC(dc);
::SetTextColor( dcMem, COLOR_WHITE );
::SetBkMode( dcMem, TRANSPARENT );
const HGDIOBJ hFont0=::SelectObject( dcMem, font );
TCHAR label[32];
const int x=timeline.GetUnitCount(cursorTime);
// . painting vertical line to indicate current position on the Timeline
if (IsFeatureShown(TCursorFeatures::TIME)){
::MoveToEx( dc, x, -500, nullptr );
::LineTo( dc, x, 500 );
const SIZE sz=font.GetTextSize( label, timeline.TimeToReadableString(cursorTime,label) );
const HGDIOBJ hBmp0=::SelectObject( dcMem, ::CreateCompatibleBitmap(dc,sz.cx,sz.cy) );
::TextOut( dcMem, 0,0, label,sizeof(label)/sizeof(TCHAR) );
::BitBlt( dc, x+4,-80, sz.cx,sz.cy, dcMem, 0,0, SRCINVERT );
::DeleteObject( ::SelectObject(dcMem,hBmp0) );
}
// . painting space between neighboring Times at current position
if (IsFeatureShown(TCursorFeatures::SPACING) && cursorTime<timeline.logTimeLength){
tr.SetCurrentTime(cursorTime);
tr.TruncateCurrentTime();
const TLogTime a=tr.GetCurrentTime(), z=tr.ReadTime();
const int xa=timeline.GetUnitCount(a), xz=timeline.GetUnitCount(z);
const SIZE sz=font.GetTextSize( label, timeline.TimeToReadableString(z-a,label) );
const HGDIOBJ hBmp0=::SelectObject( dcMem, ::CreateCompatibleBitmap(dc,sz.cx,sz.cy) );
::TextOut( dcMem, 0,0, label,sizeof(label)/sizeof(TCHAR) );
::BitBlt( dc, (xz+xa-sz.cx)/2,SPACING_HEIGHT+LINE_EXTENSION/2, sz.cx,sz.cy, dcMem, 0,0, SRCINVERT );
::DeleteObject( ::SelectObject(dcMem,hBmp0) );
::MoveToEx( dc, xa, TIME_HEIGHT, nullptr );
::LineTo( dc, xa, SPACING_HEIGHT+LINE_EXTENSION );
::MoveToEx( dc, xz, TIME_HEIGHT, nullptr );
::LineTo( dc, xz, SPACING_HEIGHT+LINE_EXTENSION );
::MoveToEx( dc, xa-LINE_EXTENSION, SPACING_HEIGHT, nullptr );
::LineTo( dc, xz+LINE_EXTENSION, SPACING_HEIGHT );
}
::SelectObject( dcMem, hFont0 );
::DeleteDC(dcMem);
}
cursorFeaturesShown=show;
}

inline TLogTime ClientPixelToTime(int pixel) const{
return std::min(
scrollTime + timeline.GetTime( pixel/Utils::LogicalUnitScaleFactor ),
Expand All @@ -150,10 +208,10 @@
// left mouse button pressed
SetFocus();
draggedTime=ClientPixelToTime( GET_X_LPARAM(lParam) );
break;
case WM_LBUTTONUP:
// left mouse button released
draggedTime=-1;
//fallthrough
case WM_ERASEBKGND:
// drawing the background
PaintCursorFeaturesInverted(false);
break;
case WM_MOUSEWHEEL:{
// mouse wheel was rotated
Expand All @@ -173,6 +231,10 @@
lParam=cursor.x;
//fallthrough
}
case WM_LBUTTONUP:
// left mouse button released
draggedTime=-1;
//fallthrough
case WM_MOUSEMOVE:
// mouse moved
if (draggedTime>=0) // left mouse button pressed
Expand All @@ -183,6 +245,11 @@
-
ClientPixelToTime( GET_X_LPARAM(lParam) )
);
else{
PaintCursorFeaturesInverted(false);
cursorTime=ClientPixelToTime( GET_X_LPARAM(lParam) );
PaintCursorFeaturesInverted(true);
}
break;
case WM_KEYDOWN:
// key pressed
Expand Down Expand Up @@ -258,6 +325,8 @@

void OnDraw(CDC *pDC) override{
// drawing the LogicalTimes
// . hiding CursorTime information
PaintCursorFeaturesInverted(false);
// . drawing the Timeline
const HDC dc=*pDC;
::SetBkMode( dc, TRANSPARENT );
Expand All @@ -281,6 +350,7 @@
, tr(tr)
, painter(*this)
, draggedTime(-1)
, cursorTime(-1) , cursorFeaturesShown(false) , cursorFeatures(TCursorFeatures::DEFAULT)
, scrollTime(0) , iwEndTimes(nullptr) {
}

Expand Down Expand Up @@ -327,6 +397,7 @@
painter.params.locker.Lock();
painter.params.id++; // stopping current painting
painter.params.locker.Unlock();
PaintCursorFeaturesInverted(false);
ScrollWindow( // "base"
(int)(timeline.GetUnitCount(scrollTime)*Utils::LogicalUnitScaleFactor) - (int)(si.nPos*Utils::LogicalUnitScaleFactor),
0
Expand Down Expand Up @@ -354,6 +425,20 @@
this->iwEndTimes=iwEndTimes;
Invalidate();
}

inline bool IsFeatureShown(TCursorFeatures cf) const{
return (cursorFeatures&cf)!=0;
}

void ToggleFeature(TCursorFeatures cf){
const bool cfs0=cursorFeaturesShown;
PaintCursorFeaturesInverted(false);
if (IsFeatureShown(cf))
cursorFeatures&=~cf;
else
cursorFeatures|=cf;
PaintCursorFeaturesInverted(cfs0);
}
} timeEditor;

#define AUTOSCROLL_HALF 64
Expand Down Expand Up @@ -476,6 +561,12 @@
case ID_ZOOM_FIT:
case IDCANCEL:
return TRUE;
case ID_TIME:
pCmdUi->SetCheck( timeEditor.IsFeatureShown(TCursorFeatures::TIME) );
return TRUE;
case ID_GAP:
pCmdUi->SetCheck( timeEditor.IsFeatureShown(TCursorFeatures::SPACING) );
return TRUE;
case ID_RECOGNIZE:
pCmdUi->SetCheck( timeEditor.GetInspectionWindowEndTimes()!=nullptr );
return TRUE;
Expand Down Expand Up @@ -506,6 +597,12 @@
case IDCANCEL:
EndDialog(nID);
return TRUE;
case ID_TIME:
timeEditor.ToggleFeature(TCursorFeatures::TIME);
return TRUE;
case ID_GAP:
timeEditor.ToggleFeature(TCursorFeatures::SPACING);
return TRUE;
case ID_RECOGNIZE:
if (timeEditor.GetInspectionWindowEndTimes()!=nullptr)
timeEditor.SetInspectionWindowEndTimes(nullptr);
Expand Down
10 changes: 10 additions & 0 deletions Main/src/Image_TrackRW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@
currentTime= R<nLogTimes ? logTime : logTimes[L];
}

void CImage::CTrackReader::TruncateCurrentTime(){
// truncates CurrentTime to the nearest lower LogicalTime
if (!iNextTime)
currentTime=0;
if (iNextTime<nLogTimes)
currentTime=logTimes[iNextTime-1];
else
currentTime=logTimes[nLogTimes-1];
}

TLogTime CImage::CTrackReader::GetIndexTime(BYTE index) const{
// returns the Time at which the specified IndexPulse occurs
if (!nLogTimes || (nIndexPulses|index)==0)
Expand Down
12 changes: 11 additions & 1 deletion Main/src/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,10 +403,20 @@ namespace Utils{
, zoomFactor(initZoomFactor) {
}

static const TCHAR TimePrefixes[]=_T("nnnµµµmmm "); // nano, micro, milli, no-prefix

int CTimeline::TimeToReadableString(TLogTime logTime,PTCHAR buffer) const{
// converts specified Time to string with same level of detail as Drawn on the timeline
BYTE unitPrefix=0;
div_t d={ logTime, 0 };
while (d.quot>=1000)
d=div(d.quot,1000), unitPrefix+=3;
return ::wsprintf( buffer, _T("%d.%03d %cs"), d.quot, d.rem, TimePrefixes[unitPrefix] );
}

void CTimeline::Draw(HDC dc,const CRideFont &font,PLogTime pOutVisibleStart,PLogTime pOutVisibleEnd) const{
// draws a timeline starting at current origin
// - determinining the primary granuality of the timeline
static const TCHAR TimePrefixes[]=_T("nnnµµµmmm "); // nano, micro, milli, no-prefix
TCHAR label[32];
TLogTime intervalBig=1, unitPrefix=0;
for( TLogTime t=logTimeLength; true; intervalBig*=10 ){
Expand Down
1 change: 1 addition & 0 deletions Main/src/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ namespace Utils{
CTimeline(TLogTime logTimeLength,TLogTime logTimePerUnit,BYTE initZoomFactor);

void SetLength(TLogTime logTime);
int TimeToReadableString(TLogTime logTime,PTCHAR buffer) const;
void Draw(HDC dc,const CRideFont &font,PLogTime pOutVisibleStart=nullptr,PLogTime pOutVisibleEnd=nullptr) const;
int GetUnitCount(TLogTime logTime,BYTE zoomFactor) const;
int GetUnitCount(TLogTime logTime) const;
Expand Down

0 comments on commit 2626649

Please sign in to comment.