GUI: reduce pattern/orders latency

no more oldOrder/oldRow hacks!
This commit is contained in:
tildearrow 2023-09-16 04:08:12 -05:00
parent 5ca710860b
commit 083f870930
8 changed files with 43 additions and 60 deletions

View file

@ -29,13 +29,13 @@ void FurnaceGUI::drawClock() {
} }
if (!clockOpen) return; if (!clockOpen) return;
if (ImGui::Begin("Clock",&clockOpen,globalWinFlags)) { if (ImGui::Begin("Clock",&clockOpen,globalWinFlags)) {
int row=e->getRow(); int row=oldRow;
int elapsedBars=e->getElapsedBars(); int elapsedBars=e->getElapsedBars();
int elapsedBeats=e->getElapsedBeats(); int elapsedBeats=e->getElapsedBeats();
bool playing=e->isPlaying(); bool playing=e->isPlaying();
if (clockShowRow) { if (clockShowRow) {
ImGui::PushFont(bigFont); ImGui::PushFont(bigFont);
ImGui::Text("%.3d:%.3d",e->getOrder(),row); ImGui::Text("%.3d:%.3d",playOrder,row);
ImGui::PopFont(); ImGui::PopFont();
} }
if (clockShowBeat) { if (clockShowBeat) {

View file

@ -1566,8 +1566,6 @@ void FurnaceGUI::doAction(int what) {
e->deleteOrder(curOrder); e->deleteOrder(curOrder);
if (curOrder>=e->curSubSong->ordersLen) { if (curOrder>=e->curSubSong->ordersLen) {
curOrder=e->curSubSong->ordersLen-1; curOrder=e->curSubSong->ordersLen-1;
oldOrder=curOrder;
oldOrder1=curOrder;
e->setOrder(curOrder); e->setOrder(curOrder);
} }
makeUndo(GUI_UNDO_CHANGE_ORDER); makeUndo(GUI_UNDO_CHANGE_ORDER);

View file

@ -1209,8 +1209,6 @@ void FurnaceGUI::doUndo() {
if (curOrder>=e->curSubSong->ordersLen) { if (curOrder>=e->curSubSong->ordersLen) {
curOrder=e->curSubSong->ordersLen-1; curOrder=e->curSubSong->ordersLen-1;
oldOrder=curOrder;
oldOrder1=curOrder;
e->setOrder(curOrder); e->setOrder(curOrder);
} }
@ -1287,8 +1285,6 @@ void FurnaceGUI::doRedo() {
if (curOrder>=e->curSubSong->ordersLen) { if (curOrder>=e->curSubSong->ordersLen) {
curOrder=e->curSubSong->ordersLen-1; curOrder=e->curSubSong->ordersLen-1;
oldOrder=curOrder;
oldOrder1=curOrder;
e->setOrder(curOrder); e->setOrder(curOrder);
} }

View file

@ -1134,7 +1134,7 @@ void FurnaceGUI::stop() {
if (followPattern && wasPlaying) { if (followPattern && wasPlaying) {
nextScroll=-1.0f; nextScroll=-1.0f;
nextAddScroll=0.0f; nextAddScroll=0.0f;
cursor.y=e->getRow(); cursor.y=oldRow;
if (selStart.xCoarse==selEnd.xCoarse && selStart.xFine==selEnd.xFine && selStart.y==selEnd.y && !selecting) { if (selStart.xCoarse==selEnd.xCoarse && selStart.xFine==selEnd.xFine && selStart.y==selEnd.y && !selecting) {
selStart=cursor; selStart=cursor;
selEnd=cursor; selEnd=cursor;
@ -4379,15 +4379,15 @@ bool FurnaceGUI::loop() {
info+=fmt::sprintf(" @ %gHz (%g BPM) ",e->getCurHz(),calcBPM(e->getSpeeds(),e->getCurHz(),e->curSubSong->virtualTempoN,e->curSubSong->virtualTempoD)); info+=fmt::sprintf(" @ %gHz (%g BPM) ",e->getCurHz(),calcBPM(e->getSpeeds(),e->getCurHz(),e->curSubSong->virtualTempoN,e->curSubSong->virtualTempoD));
if (settings.orderRowsBase) { if (settings.orderRowsBase) {
info+=fmt::sprintf("| Order %.2X/%.2X ",e->getOrder(),e->curSubSong->ordersLen-1); info+=fmt::sprintf("| Order %.2X/%.2X ",playOrder,e->curSubSong->ordersLen-1);
} else { } else {
info+=fmt::sprintf("| Order %d/%d ",e->getOrder(),e->curSubSong->ordersLen-1); info+=fmt::sprintf("| Order %d/%d ",playOrder,e->curSubSong->ordersLen-1);
} }
if (settings.patRowsBase) { if (settings.patRowsBase) {
info+=fmt::sprintf("| Row %.2X/%.2X ",e->getRow(),e->curSubSong->patLen); info+=fmt::sprintf("| Row %.2X/%.2X ",oldRow,e->curSubSong->patLen);
} else { } else {
info+=fmt::sprintf("| Row %d/%d ",e->getRow(),e->curSubSong->patLen); info+=fmt::sprintf("| Row %d/%d ",oldRow,e->curSubSong->patLen);
} }
info+=fmt::sprintf("| %d:%.2d:%.2d.%.2d",totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000); info+=fmt::sprintf("| %d:%.2d:%.2d.%.2d",totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000);
@ -4459,9 +4459,15 @@ bool FurnaceGUI::loop() {
MEASURE(calcChanOsc,calcChanOsc()); MEASURE(calcChanOsc,calcChanOsc());
e->synchronized([this]() {
playOrder=e->getOrder();
if (followPattern) { if (followPattern) {
curOrder=e->getOrder(); curOrder=playOrder;
} }
if (e->isPlaying()) {
oldRow=e->getRow();
}
});
if (mobileUI) { if (mobileUI) {
globalWinFlags=ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoBringToFrontOnFocus; globalWinFlags=ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoBringToFrontOnFocus;
@ -5540,8 +5546,6 @@ bool FurnaceGUI::loop() {
stop(); stop();
e->clearSubSongs(); e->clearSubSongs();
curOrder=0; curOrder=0;
oldOrder=0;
oldOrder1=0;
MARK_MODIFIED; MARK_MODIFIED;
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
@ -5552,8 +5556,6 @@ bool FurnaceGUI::loop() {
}); });
e->setOrder(0); e->setOrder(0);
curOrder=0; curOrder=0;
oldOrder=0;
oldOrder1=0;
MARK_MODIFIED; MARK_MODIFIED;
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
@ -5565,8 +5567,6 @@ bool FurnaceGUI::loop() {
}); });
e->setOrder(0); e->setOrder(0);
curOrder=0; curOrder=0;
oldOrder=0;
oldOrder1=0;
MARK_MODIFIED; MARK_MODIFIED;
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
@ -5671,8 +5671,6 @@ bool FurnaceGUI::loop() {
undoHist.clear(); undoHist.clear();
redoHist.clear(); redoHist.clear();
updateScroll(0); updateScroll(0);
oldOrder=0;
oldOrder1=0;
oldRow=0; oldRow=0;
cursor.xCoarse=0; cursor.xCoarse=0;
cursor.xFine=0; cursor.xFine=0;
@ -7079,10 +7077,9 @@ FurnaceGUI::FurnaceGUI():
curSample(0), curSample(0),
curOctave(3), curOctave(3),
curOrder(0), curOrder(0),
playOrder(0),
prevIns(0), prevIns(0),
oldRow(0), oldRow(0),
oldOrder(0),
oldOrder1(0),
editStep(1), editStep(1),
exportLoops(0), exportLoops(0),
soloChan(-1), soloChan(-1),

View file

@ -1806,7 +1806,7 @@ class FurnaceGUI {
DivInstrument* prevInsData; DivInstrument* prevInsData;
int curIns, curWave, curSample, curOctave, curOrder, prevIns, oldRow, oldOrder, oldOrder1, editStep, exportLoops, soloChan,orderEditMode, orderCursor; int curIns, curWave, curSample, curOctave, curOrder, playOrder, prevIns, oldRow, editStep, exportLoops, soloChan,orderEditMode, orderCursor;
int loopOrder, loopRow, loopEnd, isClipping, extraChannelButtons, newSongCategory, latchTarget; int loopOrder, loopRow, loopEnd, isClipping, extraChannelButtons, newSongCategory, latchTarget;
int wheelX, wheelY, dragSourceX, dragSourceXFine, dragSourceY, dragDestinationX, dragDestinationXFine, dragDestinationY, oldBeat, oldBar; int wheelX, wheelY, dragSourceX, dragSourceXFine, dragSourceY, dragDestinationX, dragDestinationXFine, dragDestinationY, oldBeat, oldBar;
int curGroove, exitDisabledTimer; int curGroove, exitDisabledTimer;

View file

@ -259,18 +259,18 @@ void FurnaceGUI::drawOrders() {
} }
ImGui::PushFont(patFont); ImGui::PushFont(patFont);
bool tooSmall=((displayChans+1)>((ImGui::GetContentRegionAvail().x)/(ImGui::CalcTextSize("AA").x+2.0*ImGui::GetStyle().ItemInnerSpacing.x))); bool tooSmall=((displayChans+1)>((ImGui::GetContentRegionAvail().x)/(ImGui::CalcTextSize("AA").x+2.0*ImGui::GetStyle().ItemInnerSpacing.x)));
ImGui::PopFont();
float yHeight=ImGui::GetContentRegionAvail().y; float yHeight=ImGui::GetContentRegionAvail().y;
if (ImGui::BeginTable("OrdersTable",1+displayChans,(tooSmall?ImGuiTableFlags_SizingFixedFit:ImGuiTableFlags_SizingStretchSame)|ImGuiTableFlags_ScrollX|ImGuiTableFlags_ScrollY)) {
ImGui::PushFont(patFont);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,prevSpacing);
ImGui::TableSetupScrollFreeze(1,1);
float lineHeight=(ImGui::GetTextLineHeight()+4*dpiScale); float lineHeight=(ImGui::GetTextLineHeight()+4*dpiScale);
if (e->isPlaying()) { if (e->isPlaying()) {
if (followOrders) { if (followOrders) {
ImGui::SetScrollY((e->getOrder()+1)*lineHeight-((yHeight-(tooSmall?ImGui::GetStyle().ScrollbarSize:0.0f))/2.0f)); float nextOrdScroll=(playOrder+1)*lineHeight-((yHeight-(tooSmall?ImGui::GetStyle().ScrollbarSize:0.0f))/2.0f);
if (nextOrdScroll<0.0f) nextOrdScroll=0.0f;
ImGui::SetNextWindowScroll(ImVec2(-1.0f,nextOrdScroll));
} }
} }
if (ImGui::BeginTable("OrdersTable",1+displayChans,(tooSmall?ImGuiTableFlags_SizingFixedFit:ImGuiTableFlags_SizingStretchSame)|ImGuiTableFlags_ScrollX|ImGuiTableFlags_ScrollY)) {
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,prevSpacing);
ImGui::TableSetupScrollFreeze(1,1);
ImGui::TableNextRow(0,lineHeight); ImGui::TableNextRow(0,lineHeight);
ImVec2 ra=ImGui::GetContentRegionAvail(); ImVec2 ra=ImGui::GetContentRegionAvail();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
@ -283,9 +283,9 @@ void FurnaceGUI::drawOrders() {
ImGui::PopStyleColor(); ImGui::PopStyleColor();
for (int i=0; i<e->curSubSong->ordersLen; i++) { for (int i=0; i<e->curSubSong->ordersLen; i++) {
ImGui::TableNextRow(0,lineHeight); ImGui::TableNextRow(0,lineHeight);
if (oldOrder1==i) ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_ORDER_ACTIVE])); if (playOrder==i && e->isPlaying()) ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_ORDER_ACTIVE]));
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if ((!followPattern && curOrder==i) || (followPattern && oldOrder1==i)) { if (curOrder==i) {
// draw a border // draw a border
ImDrawList* dl=ImGui::GetWindowDrawList(); ImDrawList* dl=ImGui::GetWindowDrawList();
ImVec2 rBegin=ImGui::GetCursorScreenPos(); ImVec2 rBegin=ImGui::GetCursorScreenPos();
@ -322,7 +322,7 @@ void FurnaceGUI::drawOrders() {
//} //}
ImGui::PushStyleColor(ImGuiCol_Text,(curOrder==i || e->curOrders->ord[j][i]==e->curOrders->ord[j][curOrder])?uiColors[GUI_COLOR_ORDER_SIMILAR]:uiColors[GUI_COLOR_ORDER_INACTIVE]); ImGui::PushStyleColor(ImGuiCol_Text,(curOrder==i || e->curOrders->ord[j][i]==e->curOrders->ord[j][curOrder])?uiColors[GUI_COLOR_ORDER_SIMILAR]:uiColors[GUI_COLOR_ORDER_INACTIVE]);
if (ImGui::Selectable(selID,settings.ordersCursor?(cursor.xCoarse==j && oldOrder1!=i):false)) { if (ImGui::Selectable(selID,settings.ordersCursor?(cursor.xCoarse==j && curOrder!=i):false)) {
if (curOrder==i) { if (curOrder==i) {
if (orderEditMode==0) { if (orderEditMode==0) {
prepareUndo(GUI_UNDO_CHANGE_ORDER); prepareUndo(GUI_UNDO_CHANGE_ORDER);
@ -394,9 +394,9 @@ void FurnaceGUI::drawOrders() {
} }
} }
ImGui::PopStyleVar(); ImGui::PopStyleVar();
ImGui::PopFont();
ImGui::EndTable(); ImGui::EndTable();
} }
ImGui::PopFont();
if (settings.orderButtonPos==2) { if (settings.orderButtonPos==2) {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
@ -411,6 +411,5 @@ void FurnaceGUI::drawOrders() {
} }
} }
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_ORDERS; if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_ORDERS;
oldOrder1=e->getOrder();
ImGui::End(); ImGui::End();
} }

View file

@ -91,7 +91,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
if (settings.overflowHighlight) { if (settings.overflowHighlight) {
if (edit && cursor.y==i && curWindowLast==GUI_WINDOW_PATTERN) { if (edit && cursor.y==i && curWindowLast==GUI_WINDOW_PATTERN) {
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_EDITING])); ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_EDITING]));
} else if (isPlaying && oldRow==i && ord==e->getOrder()) { } else if (isPlaying && oldRow==i && ord==playOrder) {
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_PLAY_HEAD])); ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_PLAY_HEAD]));
} else if (e->curSubSong->hilightB>0 && !(i%e->curSubSong->hilightB)) { } else if (e->curSubSong->hilightB>0 && !(i%e->curSubSong->hilightB)) {
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_HI_2])); ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_HI_2]));
@ -102,7 +102,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
isPushing=true; isPushing=true;
if (edit && cursor.y==i && curWindowLast==GUI_WINDOW_PATTERN) { if (edit && cursor.y==i && curWindowLast==GUI_WINDOW_PATTERN) {
ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_EDITING])); ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_EDITING]));
} else if (isPlaying && oldRow==i && ord==e->getOrder()) { } else if (isPlaying && oldRow==i && ord==playOrder) {
ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_PLAY_HEAD])); ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_PLAY_HEAD]));
} else if (e->curSubSong->hilightB>0 && !(i%e->curSubSong->hilightB)) { } else if (e->curSubSong->hilightB>0 && !(i%e->curSubSong->hilightB)) {
ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_HI_2])); ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_HI_2]));
@ -378,7 +378,7 @@ void FurnaceGUI::drawPattern() {
bool inhibitMenu=false; bool inhibitMenu=false;
if (e->isPlaying() && followPattern && (!e->isStepping() || pendingStepUpdate)) { if (e->isPlaying() && followPattern && (!e->isStepping() || pendingStepUpdate)) {
cursor.y=e->isStepping()?e->getRow():oldRow; cursor.y=oldRow;
if (selStart.xCoarse==selEnd.xCoarse && selStart.xFine==selEnd.xFine && selStart.y==selEnd.y && !selecting) { if (selStart.xCoarse==selEnd.xCoarse && selStart.xFine==selEnd.xFine && selStart.y==selEnd.y && !selecting) {
selStart=cursor; selStart=cursor;
selEnd=cursor; selEnd=cursor;
@ -419,8 +419,7 @@ void FurnaceGUI::drawPattern() {
} }
//char id[32]; //char id[32];
ImGui::PushFont(patFont); ImGui::PushFont(patFont);
int ord=oldOrder; int ord=curOrder;
oldOrder=curOrder;
int chans=e->getTotalChannelCount(); int chans=e->getTotalChannelCount();
int displayChans=0; int displayChans=0;
const DivPattern* patCache[DIV_MAX_CHANS]; const DivPattern* patCache[DIV_MAX_CHANS];
@ -437,23 +436,24 @@ void FurnaceGUI::drawPattern() {
ImGui::SetCursorPosX(ImGui::GetCursorPosX()+centerOff); ImGui::SetCursorPosX(ImGui::GetCursorPosX()+centerOff);
} }
} }
if (e->isPlaying() && followPattern && (!e->isStepping() || pendingStepUpdate)) updateScroll(oldRow);
if (--pendingStepUpdate<0) pendingStepUpdate=0;
if (nextScroll>-0.5f) {
ImGui::SetNextWindowScroll(ImVec2(-1.0f,nextScroll));
nextScroll=-1.0f;
nextAddScroll=0.0f;
}
if (ImGui::BeginTable("PatternView",displayChans+2,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_ScrollX|ImGuiTableFlags_ScrollY|ImGuiTableFlags_NoPadInnerX|ImGuiTableFlags_NoBordersInFrozenArea|((settings.cursorFollowsWheel || wheelCalmDown)?ImGuiTableFlags_NoScrollWithMouse:0))) { if (ImGui::BeginTable("PatternView",displayChans+2,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_ScrollX|ImGuiTableFlags_ScrollY|ImGuiTableFlags_NoPadInnerX|ImGuiTableFlags_NoBordersInFrozenArea|((settings.cursorFollowsWheel || wheelCalmDown)?ImGuiTableFlags_NoScrollWithMouse:0))) {
ImGui::TableSetupColumn("pos",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("pos",ImGuiTableColumnFlags_WidthFixed);
char chanID[2048]; char chanID[2048];
float lineHeight=(ImGui::GetTextLineHeight()+2*dpiScale); float lineHeight=(ImGui::GetTextLineHeight()+2*dpiScale);
int curRow=e->getRow();
if (e->isPlaying() && followPattern && (!e->isStepping() || pendingStepUpdate)) updateScroll(curRow);
if (--pendingStepUpdate<0) pendingStepUpdate=0;
if (nextScroll>-0.5f) {
ImGui::SetScrollY(nextScroll);
nextScroll=-1.0f;
nextAddScroll=0.0f;
}
if (nextAddScroll!=0.0f) { if (nextAddScroll!=0.0f) {
ImGui::SetScrollY(ImGui::GetScrollY()+nextAddScroll); ImGui::SetScrollY(ImGui::GetScrollY()+nextAddScroll);
nextScroll=-1.0f; nextScroll=-1.0f;
nextAddScroll=0.0f; nextAddScroll=0.0f;
} }
ImGui::TableSetupScrollFreeze(1,1); ImGui::TableSetupScrollFreeze(1,1);
for (int i=0; i<chans; i++) { for (int i=0; i<chans; i++) {
if (!e->curSubSong->chanShow[i]) continue; if (!e->curSubSong->chanShow[i]) continue;
@ -937,7 +937,6 @@ void FurnaceGUI::drawPattern() {
ImGui::EndDisabled(); ImGui::EndDisabled();
ImGui::PopStyleVar(); ImGui::PopStyleVar();
oldRow=curRow;
if (demandScrollX) { if (demandScrollX) {
int totalDemand=demandX-ImGui::GetScrollX(); int totalDemand=demandX-ImGui::GetScrollX();
if (totalDemand<80) { if (totalDemand<80) {

View file

@ -38,8 +38,6 @@ void FurnaceGUI::drawSubSongs(bool asChild) {
if (ImGui::Selectable(id,i==e->getCurrentSubSong())) { if (ImGui::Selectable(id,i==e->getCurrentSubSong())) {
e->changeSongP(i); e->changeSongP(i);
updateScroll(0); updateScroll(0);
oldOrder=0;
oldOrder1=0;
oldRow=0; oldRow=0;
cursor.xCoarse=0; cursor.xCoarse=0;
cursor.xFine=0; cursor.xFine=0;
@ -76,8 +74,6 @@ void FurnaceGUI::drawSubSongs(bool asChild) {
} else { } else {
e->changeSongP(e->song.subsong.size()-1); e->changeSongP(e->song.subsong.size()-1);
updateScroll(0); updateScroll(0);
oldOrder=0;
oldOrder1=0;
oldRow=0; oldRow=0;
cursor.xCoarse=0; cursor.xCoarse=0;
cursor.xFine=0; cursor.xFine=0;
@ -98,8 +94,6 @@ void FurnaceGUI::drawSubSongs(bool asChild) {
} else { } else {
e->changeSongP(e->song.subsong.size()-1); e->changeSongP(e->song.subsong.size()-1);
updateScroll(0); updateScroll(0);
oldOrder=0;
oldOrder1=0;
oldRow=0; oldRow=0;
cursor.xCoarse=0; cursor.xCoarse=0;
cursor.xFine=0; cursor.xFine=0;