namespace gui; import "Display" import "Anchor" import "Key" import "GuiApplication" import "Interface" import "Skin" import "Timer" import "Cursor" import "ClipBoard" import "Button" import "ListBox" import "DropBox" import "Label" import "Picture" import "ScrollBar" import "Button" import "Menu" import "StatusBar" import "ProgressBar" import "EditBox" import "DataBox" import "ToolTip" #if defined(__WIN32__) import "Win32Interface" #endif #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D) import "Desktop3D" #endif #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE) import "FormDesigner" #endif import "FileDialog" import "MessageBox" import "WindowList" import "i18n" #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) #define property _property #define new _new #define class _class #define uint _uint #define Window X11Window #define Cursor X11Cursor #define Font X11Font #define Display X11Display #define Time X11Time #define KeyCode X11KeyCode #define Picture X11Picture #include #undef Window #undef Cursor #undef Font #undef Display #undef Time #undef KeyCode #undef Picture #undef uint #undef new #undef property #undef class #endif // Had to define this here for native decorations support, because the menu bar is part of total decoration's size, but not part of the system decorations #ifdef HIGH_DPI define skinMenuHeight = 40; define statusBarHeight = 30; #else define skinMenuHeight = 25; define statusBarHeight = 18; #endif default extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown; public enum DialogResult : int64 { cancel, yes, no, ok }; public class MouseButtons { public: bool left:1, right:1, middle:1; }; public struct SizeAnchor { Size size; bool isClientW, isClientH; }; #include #define SNAPDOWN(x, d) \ if(Abs(x) % (d)) \ { \ if(x < 0) x -= ((d) - Abs(x) % (d)); else x -= x % (d); \ } #define SNAPUP(x, d) \ if(Abs(x) % (d)) \ { \ if(x > 0) x += ((d) - Abs(x) % (d)); else x += x % (d); \ } /*static */define MAX_DIRTY_BACK = 10; ///////////////////////////////////////////////////////////////////////////// ////////// EXTENT MANIPULATION ////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// #define ACCESS_ITEM(l, id) \ id #define FASTLIST_LOOP(l, v) \ for(v = (BoxItem)l.first; v; v = (BoxItem)v.next) #define FASTLIST_LOOPN(l, v, n) \ for(v = (BoxItem)l.first, n = (BoxItem)(v ? v.next : null); v; v = (BoxItem)next, n = (BoxItem)(v ? v.next : null)) /* #define ACCESS_ITEM(l, id) \ ((FastItem)(((id) == -1) ? null : (((byte *)((l).items)) + (id) * (l).itemSize))) #define FASTLIST_LOOP(l, v) \ for(v = (void *)ACCESS_ITEM((l), (l).first); v; v = (void *)ACCESS_ITEM((l), v.next)) #define FASTLIST_LOOPN(l, v, n) \ for( v = (void *)ACCESS_ITEM((l), (l).first), \ n = v ? ((void *)ACCESS_ITEM((l), v.next)): null; \ v; v = n, n = n ? (void *)ACCESS_ITEM((l), n.next) : null) private class FastItem : struct { int prev, next; }; private struct FastList { FastItem items; int first, last; int free; int count, size, itemSize; void Clear(void) { count = 0; size = 0; items = null; first = last = free = -1; itemSize = 0; } void Empty(void) { FastItem item, next; Free(); // FASTLIST_LOOPN(this, item, next) { Delete(item); }; } FastItem Add(uint itemSize) { FastItem item; if(free == -1 || !size) { int c; int newSize; if(size) { newSize = (size + (size >> 1)); items = (FastItem)renew items byte[newSize * itemSize]; } else { newSize = 4; this.itemSize = itemSize; items = (FastItem)new byte[newSize * itemSize]; } for(c = size; c extentBox.box.left) extentBox.box.left = box.left; if(box.top > extentBox.box.top) extentBox.box.top = box.top; if(box.right < extentBox.box.right) extentBox.box.right = box.right; if(box.bottom < extentBox.box.bottom) extentBox.box.bottom = box.bottom; if(extentBox.box.right < extentBox.box.left || extentBox.box.bottom < extentBox.box.top) Delete(extentBox); } } void ExcludeBox(Box box, Extent temp) { BoxItem extentBox; temp.Copy(this); Empty(); for(extentBox = (BoxItem)temp.first; extentBox; extentBox = (BoxItem)extentBox.next) { if(extentBox.box.left < box.right && extentBox.box.right > box.left && extentBox.box.top < box.bottom && extentBox.box.bottom > box.top) { // Top box if(extentBox.box.top < box.top && extentBox.box.bottom >= box.top) { Box newBox { extentBox.box.left, extentBox.box.top, extentBox.box.right, Min(extentBox.box.bottom, box.top -1) }; AddBox(newBox); } // Bottom box if(extentBox.box.bottom > box.bottom && extentBox.box.top <= box.bottom) { Box newBox { extentBox.box.left, Max(extentBox.box.top,box.bottom +1), extentBox.box.right, extentBox.box.bottom }; AddBox(newBox); } // Middle boxes if(extentBox.box.bottom >= box.top && extentBox.box.top <= box.bottom) { // Left box if(extentBox.box.left < box.left && extentBox.box.right >= box.left) { Box newBox { extentBox.box.left, Max(extentBox.box.top, box.top), Min(extentBox.box.right, box.left-1), Min(extentBox.box.bottom, box.bottom) }; AddBox(newBox); } // Right box if(extentBox.box.right > box.right && extentBox.box.left <= box.right) { Box newBox { Max(extentBox.box.left, box.right+1), Max(extentBox.box.top, box.top), extentBox.box.right, Min(extentBox.box.bottom, box.bottom) }; AddBox(newBox); } } } else { AddBox(extentBox.box); } } temp.Empty(); } void UnionBox(Box box, Extent temp) { BoxItem extentBox, next; // First pass: check if this box is not already covered by one of the extent's box for(extentBox = (BoxItem)this.first; extentBox; extentBox = (BoxItem)extentBox.next) { if(extentBox.box.left <= box.left && extentBox.box.right >= box.right && extentBox.box.top <= box.top && extentBox.box.bottom >= box.bottom) { // No change return; } } // Second pass: only keep boxes not completely covered in the new box for(extentBox = (BoxItem)this.first; extentBox; extentBox = next) { next = (BoxItem)extentBox.next; if(extentBox.box.left >= box.left && extentBox.box.right <= box.right && extentBox.box.top >= box.top && extentBox.box.bottom <= box.bottom) Delete(extentBox); } // Add the exclusion to the extent ExcludeBox(box, temp); // Add the new box if(box.bottom >= box.top && box.right >= box.left) { // Optimization: if the resulting boxes touch, add them smarter for(extentBox = (BoxItem)this.first; extentBox; extentBox = (BoxItem)extentBox.next) { if(box.top == extentBox.box.top && box.bottom == extentBox.box.bottom) { if(Abs(box.right - extentBox.box.left) <= 1) { extentBox.box.left = box.left; break; } else if(Abs(box.left - extentBox.box.right) <= 1) { extentBox.box.right = box.right; break; } } else if(box.left == extentBox.box.left && box.right == extentBox.box.right) { if(Abs(box.bottom - extentBox.box.top) <= 1) { extentBox.box.top = box.top; break; } else if(Abs(box.top - extentBox.box.bottom) <= 1) { extentBox.box.bottom = box.bottom; break; } } } // Else, add it if(!extentBox) AddBox(box); } } void Union(Extent b, Extent temp) { BoxItem extentBox; for(extentBox = (BoxItem)b.first; extentBox; extentBox = (BoxItem)extentBox.next) UnionBox(extentBox.box, temp); } void Intersection(Extent b, Extent temp, Extent temp2, Extent temp3) { BoxItem extentBox; temp.Copy(this); Empty(); for(extentBox = (BoxItem)b.first; extentBox; extentBox = (BoxItem)extentBox.next) { temp2.Copy(temp); temp2.IntersectBox(extentBox.box); Union(temp2, temp3); temp2.Empty(); } temp.Empty(); } void Exclusion(Extent b, Extent temp) { BoxItem extentBox; for(extentBox = (BoxItem)b.first; extentBox; extentBox = (BoxItem)extentBox.next) ExcludeBox(extentBox.box, temp); } void Offset(int x, int y) { BoxItem extentBox; for(extentBox = (BoxItem)this.first; extentBox; extentBox = (BoxItem)extentBox.next) { extentBox.box.left += x; extentBox.box.top += y; extentBox.box.right += x; extentBox.box.bottom += y; } } }; private define MINIMIZED_WIDTH = 160; private define CASCADE_SPACE = 16; // namespace Windows; private class ScrollFlags { bool snapX:1, snapY:1, dontHide:1; }; public class BorderBits { public: bool contour:1, fixed:1, sizable:1, deep:1, bevel:1, thin:1; }; class WindowBits : BorderBits { BorderBits borderBits:6:0; bool hidden:1, isActiveClient:1, hasHorzScroll:1, hasVertScroll:1, stayOnTop:1, modal:1, isDefault:1, inactive:1, isRemote:1, drawBehind:1; bool interim:1, tabCycle:1, noCycle:1, dontScrollHorz:1, dontScrollVert:1, hasMaximize:1, hasMinimize:1, hasClose:1; bool embedded:1, hasMenuBar:1, isDocument:1, showInTaskBar:1, hasStatusBar:1, nonClient:1, clickThrough:1; }; public enum BorderStyle : BorderBits { none, contour = BorderBits { contour = true }, fixed = BorderBits { fixed = true } | contour, sizable = BorderBits { sizable = true } | fixed, thin = BorderBits { fixed = true, thin = true } | contour, sizableThin = BorderBits { sizable = true } | thin, deep = BorderBits { deep = true }, bevel = BorderBits { bevel = true }, sizableDeep = sizable|deep, sizableBevel = sizable|bevel, fixedDeep = fixed|deep, fixedBevel = fixed|bevel, deepContour = deep|contour }; public enum CreationActivationOption { activate, flash, doNothing }; public enum WindowState { normal, minimized, maximized }; private class ResPtr : struct { ResPtr prev, next; Resource resource; void * loaded; }; private class HotKeySlot : struct { HotKeySlot prev, next; Window window; Key key; }; public struct TouchPointerInfo { int id; Point point; float size, pressure; }; public enum TouchPointerEvent { move, up, down, pointerUp, pointerDown }; public class Window { private: class_data const char * icon; class_no_expansion class_default_property caption; // class_initialize GuiApplication::Initialize; class_designer FormDesigner; class_property const char * icon { set { class_data(icon) = value; } get { return class_data(icon); } } Window() { bool switchMode = true; #if defined(__ANDROID__) switchMode = false; fullRender = true; #endif if(guiApp) guiApp.Initialize(switchMode); if(guiApp && guiApp.currentSkin && ((subclass(Window))_class).pureVTbl) { if(_vTbl == ((subclass(Window))_class).pureVTbl) { _vTbl = _class._vTbl; } else if(_vTbl != _class._vTbl) { int m; for(m = 0; m < _class.vTblSize; m++) { if(_vTbl[m] == ((subclass(Window))_class).pureVTbl[m]) _vTbl[m] = _class._vTbl[m]; } } } //tempExtents[0] = { /*first = -1, last = -1, free = -1*/ }; //tempExtents[1] = { /*first = -1, last = -1, free = -1*/ }; //tempExtents[2] = { /*first = -1, last = -1, free = -1*/ }; //tempExtents[3] = { /*first = -1, last = -1, free = -1*/ }; setVisible = true; // caption = CopyString(class.name); children.offset = (byte*)&prev - (byte*)this; childrenOrder.circ = true; childrenCycle.circ = true; maxSize = Size { MAXINT, MAXINT }; background = white; foreground = black; //style.isActiveClient = true; mergeMenus = true; autoCreate = true; modifyVirtArea = true; manageDisplay = true; nativeDecorations = true; // scrollFlags = ScrollFlags { snapX = true, snapY = true }; sbStep.x = sbStep.y = 8; if(guiApp) // dynamic_cast(thisModule) { cursor = guiApp.GetCursor(arrow); property::parent = guiApp.desktop; } } ~Window() { Window child; OldLink slave; ResPtr ptr; #if !defined(__EMSCRIPTEN__) if(fileMonitor) { int i, lockCount = guiApp.lockMutex.lockCount; #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) if(xGlobalDisplay) XUnlockDisplay(xGlobalDisplay); #endif for(i = 0; i < lockCount; i++) guiApp.lockMutex.Release(); delete fileMonitor; for(i = 0; i < lockCount; i++) guiApp.lockMutex.Wait(); #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) if(xGlobalDisplay) XLockDisplay(xGlobalDisplay); #endif } #endif if(parent) { stopwatching(parent, font); if(parent.activeChild == this) parent.activeChild = null; if(parent.activeClient == this) parent.activeClient = null; } if(!destroyed) { // Prevent destructor from being called again... incref this; incref this; DestroyEx(0); } ///////////////////////////////// if(master) { OldLink slave = master.slaves.FindLink(this); master.slaves.Delete(slave); master = null; } if(parent) { if(cycle) parent.childrenCycle.Remove(cycle); if(order) parent.childrenOrder.Remove(order); parent.children.Remove(this); parent = null; } delete cycle; delete order; ///////////////////////////////// while((ptr = resources.first)) { delete ptr.resource; resources.Delete(ptr); } usedFont = null; delete setFont; delete systemFont; for(child = children.first; child; child = child.next) { // child.stopwatching(this, font); if(child.parent) eInstance_StopWatching(this, __ecereProp___ecereNameSpace__ecere__gui__Window_font, child); // Don't want property here *&child.parent = null; } while((slave = slaves.first)) { // Don't want property here *&((Window)slave.data).master = null; slaves.Delete(slave); } // Because we do a decref in DestroyEx... if(!destroyed) { incref this; incref this; DestroyEx(0); } // Why was this commented? //if(this != guiApp.desktop) { delete caption; delete fileName; } delete menu; delete statusBar; OnDestroyed(); #if !defined(__EMSCRIPTEN__) delete mutex; #endif delete icon; if(((subclass(Window))_class).pureVTbl) { if(_vTbl == _class._vTbl) { _vTbl = ((subclass(Window))_class).pureVTbl; } else { int m; for(m = 0; m < _class.vTblSize; m++) { if(_vTbl[m] == _class._vTbl[m]) _vTbl[m] = ((subclass(Window))_class).pureVTbl[m]; } } } if(_vTbl == ((subclass(Window))_class).pureVTbl || _vTbl == _class._vTbl) _vTbl = null; dirtyArea.Free(null); renderArea.Free(null); overRenderArea.Free(null); clipExtent.Free(null); scrollExtent.Free(null); dirtyBack.Free(null); if(tempExtents) { tempExtents[0].Free(null); tempExtents[1].Free(null); tempExtents[2].Free(null); tempExtents[3].Free(null); delete tempExtents; } delete controller; } //#if !defined(ECERE_VANILLA) const char * OnGetString(char * stringOutput, void * fieldData, bool * needClass) { if(this == activeDesigner) return "(Desktop)"; else { const char * name = property::name; return name ? name : ""; } } //#endif #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE) bool OnGetDataFromString(const char * string) { FormDesigner designer = (FormDesigner)activeDesigner.classDesigner; if(string[0]) { if(!strcmp(string, "this") || !strcmp(string, designer.form.name)) this = designer.form; else if(!strcmpi(string, "(Desktop)")) this = activeDesigner; else return activeDesigner.FindObject(&this, string); } return true; } #endif // --- Window updates system --- // Setup a bitmap for Redrawing on client area of Window Surface Redraw(Box box) { Surface surface = null; Box mox = box; Box clientArea = this.clientArea; SetBox(clientArea); mox.left -= clientStart.x; mox.top -= clientStart.y; mox.right -= clientStart.x; mox.bottom -= clientStart.y; mox.Clip(clientArea); // mox.ClipOffset(against, scrolledPos.x, scrolledPos.y); if((!guiApp.fullScreenMode || guiApp.desktop.active) && display && mox.right >= mox.left && mox.bottom >= mox.top) { int x = absPosition.x + clientStart.x; int y = absPosition.y + clientStart.y; if(rootWindow.nativeDecorations && rootWindow.windowHandle && !is3D) { x -= rootWindow.clientStart.x; y -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0); } if(!guiApp.fullScreenMode || is3D) { x -= rootWindow.absPosition.x; y -= rootWindow.absPosition.y; if(rootWindow.is3D) { int dx = rootWindow.parent.parent.clientStart.x; int dy = rootWindow.parent.parent.clientStart.y; if(!rootWindow.parent.nativeDecorations) { dx += rootWindow.parent.clientStart.x; dy += rootWindow.parent.clientStart.y; } x += dx; y += dy; /* mox.left += dx; mox.top += dy; mox.right += dx; mox.bottom += dy; */ } } surface = display.GetSurface(x, y, mox); /*if(surface) { surface.width = clientSize.w; surface.height = clientSize.h; }*/ } return surface; } // Setup a bitmap for Redrawing on full Window Surface RedrawFull(Box box) { Surface surface = null; Box mox; if(box != null) box.Clip(this.box); else box = &this.box; mox = box; if((!guiApp.fullScreenMode || guiApp.desktop.active) && display && box.right >= box.left && box.bottom >= box.top) { int x = absPosition.x; int y = absPosition.y; if(rootWindow.nativeDecorations && rootWindow.windowHandle && !is3D) { x -= rootWindow.clientStart.x; y -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0); } #if !defined(__EMSCRIPTEN__) if(!guiApp.fullScreenMode || is3D) #endif { x -= rootWindow.absPosition.x; y -= rootWindow.absPosition.y; if(rootWindow.is3D) { int dx = rootWindow.parent.parent.clientStart.x; int dy = rootWindow.parent.parent.clientStart.y; if(!rootWindow.parent.nativeDecorations) { dx += rootWindow.parent.clientStart.x; dy += rootWindow.parent.clientStart.y; } x += dx; y += dy; /* mox.left += dx; mox.top += dy; mox.right += dx; mox.bottom += dy; */ } } surface = display.GetSurface(x, y, mox); /*if(surface) { surface.width = size.w; surface.height = size.h; }*/ } return surface; } void FigureCaption(char * caption) { Window activeClient = null; caption[0] = '\0'; if(this.caption) strcpy(caption, this.caption); if(style.isDocument || fileName) { if(caption[0]) strcat(caption, " - "); if(fileName) strcat(caption, fileName); else { char title[256]; sprintf(title, "Untitled %d", documentID); strcat(caption, title); } if(modifiedDocument) strcat(caption, " *"); } if(menuBar) { for(activeClient = this.activeClient; activeClient && !((BorderBits)activeClient.borderStyle).fixed; activeClient = activeClient.activeClient); } if(activeClient && activeClient.state == maximized) { if(activeClient.caption) { if(caption[0]) strcat(caption, " - "); strcat(caption, activeClient.caption); } if(activeClient.style.isDocument || activeClient.fileName) { if(caption[0]) strcat(caption, " - "); strcat(caption, "["); if(activeClient.fileName) strcat(caption, activeClient.fileName); else { char title[256]; sprintf(title, "Untitled %d", activeClient.documentID); strcat(caption, title); } if(activeClient.modifiedDocument) strcat(caption, " *"); strcat(caption, "]"); } } } // Code for returning dirty from ScrollDisplay: /* for(d = 0; d= cascade && (state == normal /*|| state == Hidden*/)) { // Leave room for non client windows (eventually dockable panels) Window win; int loX = 0, loY = 0, hiX = pw, hiY = ph; for(win = parent.children.first; win; win = win.next) { if(!win.nonClient && !win.isActiveClient && win.visible) { Size size = win.size; Point pos = win.position; int left = pos.x, top = pos.y; int right = pos.x + size.w, bottom = pos.y + size.h; if(win.size.w > win.size.h) { if(bottom < ph / 4) loY = Max(loY, bottom); else if(top > ph - ph / 4) hiY = Min(hiY, top); } else { if(right < pw / 4) loX = Max(loX, right); else if(left > pw - pw / 4) hiX = Min(hiX, left); } } } xOffset = loX; yOffset = loY; pw = hiX - loX; ph = hiY - loY; if(parent.sbv && !parent.sbv.style.hidden) pw += guiApp.currentSkin.VerticalSBW(); if(parent.sbh && !parent.sbh.style.hidden) ph += guiApp.currentSkin.HorizontalSBH(); if(anchor.left.type == cascade) { w = (int)(pw * 0.80); h = (int)(ph * 0.80); } else if(anchor.left.type >= vTiled) { int leftOver; int x2, y2; numTiling = parent.numPositions - parent.numIcons; if(parent.numIcons) ph -= guiApp.textMode ? 16 : 24; if(anchor.left.type == vTiled) { if(numTiling) { tilingH = (int)sqrt(numTiling); tilingW = numTiling / tilingH; } else tilingH = tilingW = 0; } else { if(numTiling) { tilingW = (int)sqrt(numTiling); tilingH = numTiling / tilingW; } else tilingH = tilingW = 0; } leftOver = numTiling - tilingH * tilingW; if(leftOver) { tilingSplit = (tilingW - leftOver) * tilingH; tilingLastH = tilingH+1; } else tilingSplit = numTiling; if(tilingW && tilingH) { if(positionID >= tilingSplit) { x = xOffset + pw * (tilingSplit / tilingH + (positionID - tilingSplit) / tilingLastH)/tilingW; y = yOffset + ph * ((positionID - tilingSplit) % tilingLastH) / tilingLastH; x2 = xOffset + pw * (tilingSplit/tilingH + (positionID - tilingSplit) / tilingLastH + 1)/tilingW; y2 = yOffset + ph * (((positionID - tilingSplit) % tilingLastH) + 1) / tilingLastH; } else { x = xOffset + pw * (positionID / tilingH) / tilingW; y = yOffset + ph * (positionID % tilingH) / tilingH; x2 = xOffset + pw * (positionID / tilingH + 1) / tilingW; y2 = yOffset + ph * ((positionID % tilingH) + 1) / tilingH; } } else { // How can this happen? From ec2 parsing test x = 0; y = 0; x2 = 0; y2 = 0; } if(guiApp.textMode) { SNAPDOWN(x, textCellW); SNAPDOWN(y, textCellH); SNAPDOWN(x2, textCellW); SNAPDOWN(y2, textCellH); } w = x2 - x; h = y2 - y; } } else { if(sizeAnchor.isClientW) w += ew; if(sizeAnchor.isClientH) h += eh; if(anchor.left.type == offset) x = anchor.left.distance; else if(anchor.left.type == relative) x = (anchor.left.percent < 0) ? ((int)(vpw * anchor.left.percent - 0.5)) : (int)(vpw * anchor.left.percent + 0.5); else if(anchor.right.type == relative) // ex = (anchor.right.percent < 0) ? ((int)(vpw * anchor.right.percent + 0)) : ((int)(vpw * anchor.right.percent + 0)); ex = (anchor.right.percent < 0) ? ((int)(vpw * (1.0-anchor.right.percent) + 0)) : ((int)(vpw * (1.0-anchor.right.percent) + 0)); else if(anchor.right.type == offset) ex = vpw - anchor.right.distance; if(anchor.top.type == offset) y = anchor.top.distance; else if(anchor.top.type == relative) y = (anchor.top.percent < 0) ? ((int)(vph * anchor.top.percent - 0.5)) : ((int)(vph * anchor.top.percent + 0.5)); else if(anchor.bottom.type == relative) //ey = (anchor.bottom.percent < 0) ? ((int)(vph * anchor.bottom.percent + 0)) : ((int)(vph * anchor.bottom.percent + 0)); ey = (anchor.bottom.percent < 0) ? ((int)(vph * (1.0-anchor.bottom.percent) + 0)) : ((int)(vph * (1.0-anchor.bottom.percent) + 0)); else if(anchor.bottom.type == offset) ey = vph - anchor.bottom.distance; if(anchor.left.type && anchor.right.type) { switch(anchor.right.type) { case relative: ex = pw * (1.0f-anchor.right.percent); w = Max((int)(ex + 0.5) - x, 0); break; case offset: ex = vpw - anchor.right.distance; w = Max((int)(ex + 0.5) - x, 0); break; } } if(anchor.top.type && anchor.bottom.type) { switch(anchor.bottom.type) { case relative: ey = ph * (1.0f-anchor.bottom.percent); h = Max((int)(ey + 0.5) - y, 0); break; case offset: ey = vph - anchor.bottom.distance; h = Max((int)(ey + 0.5) - y, 0); break; } } } w -= ew; h -= eh; if(state == normal /*|| state == Hidden*/) { bool addSbV = false, addSbH = false; if(sizeAnchor.isClientW || (anchor.left.type && anchor.right.type)) w = Max(w, 1); else w = Max(w, 0); if(sizeAnchor.isClientH || (anchor.top.type && anchor.bottom.type)) h = Max(h, 1); else h = Max(h, 0); w = Max(w, minSize.w); h = Max(h, minSize.h); w = Min(w, maxSize.w); h = Min(h, maxSize.h); if((sizeAnchor.isClientW || !w || (anchor.left.type && anchor.right.type)) && reqScrollArea.h > h /*&& w*/ && sbv) { if(w) w -= guiApp.currentSkin.VerticalSBW(); addSbV = true; } if((sizeAnchor.isClientH || !h || (anchor.top.type && anchor.bottom.type)) && reqScrollArea.w > w /*&& h*/ && sbh) { if(h) h -= guiApp.currentSkin.HorizontalSBH(); addSbH = true; } if(!OnResizing(&w, &h)) { w = clientSize.w; h = clientSize.h; } if((addSbV)) // || reqScrollArea.h > h) && sbv) w += guiApp.currentSkin.VerticalSBW(); if((addSbH)) // || reqScrollArea.w > w) && sbh) h += guiApp.currentSkin.HorizontalSBH(); w = Max(w, skinMinSize.w); h = Max(h, skinMinSize.h); } else { w = Max(w, 0); h = Max(h, 0); } w += ew; h += eh; if(guiApp.textMode) { SNAPDOWN(w, textCellW); SNAPDOWN(h, textCellH); } if(anchor.left.type == cascade && (state == normal /*|| state == Hidden*/)) { if(parent.numIcons) ph -= guiApp.textMode ? 16 : 24; numCascade = Min( (pw - w) / CASCADE_SPACE, (ph - h) / CASCADE_SPACE); if(guiApp.textMode) { int cascW, cascH; numCascade++; cascW = (pw - w) / (numCascade-1); cascH = (ph - h) / (numCascade-1); SNAPDOWN(cascW, textCellW); SNAPDOWN(cascH, textCellH); cascadeW = (float)cascW; cascadeH = (float)cascH; } else { numCascade = Max(numCascade, 2); cascadeW = (float)(pw - w) / (numCascade-1); cascadeH = (float)(ph - h) / (numCascade-1); } x = (int)((positionID % numCascade) * cascadeW) + xOffset; y = (int)((positionID % numCascade) * cascadeH) + yOffset; } else if(anchor.left.type < vTiled) { if(!anchor.left.type || anchor.horz.type == middleRelative) { if(!anchor.right.type) { if(anchor.horz.type == middleRelative) x = (int)(vpw * (0.5 + anchor.horz.percent) - w / 2); else x = vpw / 2 + anchor.horz.distance - w / 2; } else x = (int)(ex - w); } // case A_EDGE: x = x - w; break; if(!anchor.top.type || anchor.vert.type == middleRelative) { if(!anchor.bottom.type) { if(anchor.vert.type == middleRelative) y = (int)(vph * (0.5 + anchor.vert.percent) - h / 2); else y = vph / 2 + anchor.vert.distance - h / 2; } else y = (int)(ey - h); } // case A_EDGE: y = y - h; break; } if((state == normal /*|| state == Hidden*/) && !OnMoving(&x, &y, w, h)) { x = position.x; y = position.y; } if(guiApp.textMode) { SNAPDOWN(x, textCellW); SNAPDOWN(y, textCellH); } x += addX; y += addY; *ow = w; *oh = h; *ox = x; *oy = y; if(anchored && style.fixed && style.isActiveClient) anchored = false; } // --- Carets --- void UpdateCaret(bool forceUpdate, bool erase) { static Window lastWindow = null; static int caretX, caretY, caretSize; if(guiApp && guiApp.caretOwner == this) { int x = caretPos.x - scroll.x; int y = caretPos.y - scroll.y; if((erase || this.caretSize) && x >= clientArea.left && x <= clientArea.right && y >= clientArea.top && y <= clientArea.bottom) { if(!erase) { guiApp.interfaceDriver.SetCaret( x + absPosition.x + clientStart.x, y + absPosition.y + clientStart.y, this.caretSize); guiApp.caretEnabled = true; } if(erase || lastWindow != this || caretX != x || caretY != y || caretSize != this.caretSize || forceUpdate) { Box updateBox; if(lastWindow != this) { updateBox.left = x + 1; updateBox.top = y; updateBox.right = x + 2; updateBox.bottom = y + this.caretSize - 1; } else { updateBox.left = Min(x + 1, caretX + 1); updateBox.top = Min(y, caretY); updateBox.right = Max(x + 2, caretX + 2); updateBox.bottom = Max(y + this.caretSize - 1, caretY + caretSize - 1); } guiApp.caretOwner.Update(updateBox); if(!erase) { lastWindow = this; caretX = x; caretY = y; caretSize = this.caretSize; } } } else { guiApp.interfaceDriver.SetCaret(0,0,0); guiApp.caretEnabled = false; lastWindow = null; } } } void SetPosition(int x, int y, int w, int h, bool modifyArea, bool modifyThisArea, bool modifyClientArea) { Window child; // Set position scrolledPos.x = position.x = x; scrolledPos.y = position.y = y; clientSize.w = size.w = w; clientSize.h = size.h = h; if(parent && !style.nonClient) { //if(!style.fixed || style.isDocument) { if(!style.dontScrollHorz) scrolledPos.x -= parent.scroll.x; if(!style.dontScrollVert) scrolledPos.y -= parent.scroll.y; } } clientStart.x = clientStart.y = 0; SetWindowArea(&clientStart.x, &clientStart.y, &size.w, &size.h, &clientSize.w, &clientSize.h); //if(!activeClient || activeClient.state != maximized) if(!noAutoScrollArea) { // Check if scroll area must be modified if(guiApp && !guiApp.modeSwitching && (sbv || sbh)) { bool foundChild = false; int w = 0, h = 0; int cw = clientSize.w;// + ((!sbv || sbv.range > 1) ? guiApp.currentSkin.VerticalSBW() : 0); int ch = clientSize.h;// + ((!sbh || sbh.rangw > 1) ? guiApp.currentSkin.HorizontalSBH() : 0); for(child = children.first; child; child = child.next) { if(child.modifyVirtArea && !child.style.hidden && child.created && /*!child.anchored &&*/ !child.style.dontScrollHorz && !child.style.dontScrollVert && !child.style.nonClient) { if(child.stateAnchor.right.type == none && child.stateAnchor.left.type == offset) w = Max(w, child.position.x + child.size.w); else if(child.stateAnchor.right.type == none && child.stateAnchor.left.type == none) w = Max(w, Max(child.position.x, 0) + child.size.w); if(child.stateAnchor.bottom.type == none && child.stateAnchor.top.type == offset) h = Max(h, child.position.y + child.size.h); else if(child.stateAnchor.bottom.type == none && child.stateAnchor.top.type == none) h = Max(h, Max(child.position.y, 0) + child.size.h); foundChild = true; } } if(foundChild && (w > cw || h > ch)) { //if((w > reqScrollArea.w) || (h > reqScrollArea.w)) { int stepX = sbStep.x, stepY = sbStep.y; // Needed to make snapped down position match the skin's check of client area // against realvirtual if(guiApp.textMode) { SNAPDOWN(stepX, textCellW); SNAPDOWN(stepY, textCellH); stepX = Max(stepX, textCellW); stepY = Max(stepY, textCellH); } if(scrollFlags.snapX) SNAPUP(w, stepX); if(scrollFlags.snapY) SNAPUP(h, stepY); reqScrollArea.w = w; reqScrollArea.h = h; } } else if(reqScrollArea.w || reqScrollArea.h) { reqScrollArea.w = 0; reqScrollArea.h = 0; SetScrollPosition(0,0); } } } // Automatic MDI Client Scrolling Area Adjustment if(parent && !parent.noAutoScrollArea) { if(modifyArea && modifyVirtArea /*&& !anchored*/ && (parent.sbv || parent.sbh) && !style.dontScrollHorz && !style.dontScrollVert && !style.nonClient) { Window parent = this.parent; int w = parent.reqScrollArea.w; int h = parent.reqScrollArea.h; if(stateAnchor.right.type == none && stateAnchor.left.type == offset) w = Max(w, position.x + size.w); else if(stateAnchor.right.type == none && stateAnchor.left.type == none) w = Max(w, Max(position.x, 0) + size.w); if(stateAnchor.bottom.type == none && stateAnchor.top.type == offset) h = Max(h, position.y + size.h); else if(stateAnchor.bottom.type == none && stateAnchor.top.type == none) h = Max(h, Max(position.y, 0) + size.h); if((w > parent.clientSize.w && w > parent.reqScrollArea.w) || (h > parent.clientSize.h && h > parent.reqScrollArea.h)) { /*bool resize = false; int stepX = parent.sbStep.x, stepY = parent.sbStep.y; // Needed to make snapped down position match the skin's check of client area // against realvirtual if(guiApp.textMode) { SNAPDOWN(stepX, textCellW); SNAPDOWN(stepY, textCellH); stepX = Max(stepX, textCellW); stepY = Max(stepY, textCellH); } if(parent.scrollFlags.snapX) SNAPUP(w, stepX); if(parent.scrollFlags.snapY) SNAPUP(h, stepY); if(parent.reqScrollArea.w != w || parent.reqScrollArea.h != h) { parent.reqScrollArea.w = w; parent.reqScrollArea.h = h;*/ // parent.UpdateScrollBars(true, true); parent.Position(parent.position.x, parent.position.y, parent.size.w, parent.size.h, false, true, true, true, false, false); return; //} } else GetRidOfVirtualArea(); } } if(modifyThisArea) UpdateScrollBars(modifyThisArea, false); else if(guiApp.currentSkin) { SetWindowArea( &clientStart.x, &clientStart.y, &size.w, &size.h, &clientSize.w, &clientSize.h); if(sbv && (scrollFlags.dontHide || sbv.range > 1)) clientSize.w -= guiApp.currentSkin.VerticalSBW(); if(sbh && (scrollFlags.dontHide || sbh.range > 1)) clientSize.h -= guiApp.currentSkin.HorizontalSBH(); } scrollArea.w = Max(clientSize.w, reqScrollArea.w); scrollArea.h = Max(clientSize.h, reqScrollArea.h); absPosition = scrolledPos; if(guiApp && guiApp.driver != null && guiApp.interfaceDriver) guiApp.interfaceDriver.OffsetWindow(this, &absPosition.x, &absPosition.y); if(this != guiApp.desktop && parent) { absPosition.x += parent.absPosition.x; absPosition.y += parent.absPosition.y; if(!style.nonClient && this != guiApp.desktop) { absPosition.x += parent.clientStart.x; absPosition.y += parent.clientStart.y; } } box = Box { 0, 0, size.w - 1, size.h - 1 }; SetBox(box); if(against) { // Clip against parent's client area box.ClipOffset(against, scrolledPos.x, scrolledPos.y); } // Compute client area in this window coordinate system clientArea.left = 0; clientArea.top = 0; clientArea.right = clientSize.w - 1; clientArea.bottom = clientSize.h - 1; // Clip against parent's client area if(against) clientArea.ClipOffset(against, scrolledPos.x + clientStart.x, scrolledPos.y + clientStart.y); if(is3D) { //absPosition.x -= parent.clientStart.x; //absPosition.y -= parent.clientStart.y; } // Adjust all children for(child = children.first; child; child = child.next) child.SetPosition(child.position.x, child.position.y, child.size.w, child.size.h, false, true, true); UpdateCaret(false, false); } void GetRidOfVirtualArea(void) { if(parent && !parent.destroyed && style.fixed && !style.dontScrollHorz && !style.dontScrollVert && !style.nonClient && parent.reqScrollArea.w && parent.reqScrollArea.h) { if(!parent.noAutoScrollArea) { // TODO: Review the logic of all this? Each child is going to reposition the parent? /* Window child; bool found = false; for(child = children.first; child; child = child.next) { if(child.modifyVirtArea && !child.style.dontScrollHorz && !child.style.dontScrollVert && !child.style.nonClient) { if(child.position.x + child.size.w > parent.clientSize.w + ((!parent.sbv || parent.sbv.style.hidden) ? 0 : guiApp.currentSkin.VerticalSBW()) || child.position.y + child.size.h > parent.clientSize.h + ((!parent.sbh || parent.sbh.style.hidden) ? 0 : guiApp.currentSkin.HorizontalSBH())) { found = true; break; } } } if(!found) */ { Window parent = this.parent; parent.Position( parent.position.x, parent.position.y, parent.size.w, parent.size.h, false, true, true, true, false, false); /* parent.SetScrollArea(0,0,true); parent.SetScrollPosition(0,0); */ } } } } public void ExternalPosition(int x, int y, int w, int h) { Position(x, y, w, h, false, true, true, true, false, false); } // (w, h): Full window size bool Position(int x, int y, int w, int h, bool force, bool processAnchors, bool modifyArea, bool updateScrollBars, bool thisOnly, bool changeRootWindow) { bool result = false; int oldCW = clientSize.w, oldCH = clientSize.h; bool clientResized, windowResized, windowMoved; Window child; //bool realResized = size.w != w || size.h != h; // TOCHECK: This wasn't in ecere.dll //if(!parent) return true; if(destroyed) return false; windowMoved = position.x != x || position.y != y || force; // windowResized = realResized || force; windowResized = size.w != w || size.h != h || force; if(rootWindow != this && display && !display.flags.flipping && scrolledPos.x != MININT) { if(style.nonClient) { Box box { scrolledPos.x - parent.clientStart.x + this.box.left, scrolledPos.y - parent.clientStart.y + this.box.top, scrolledPos.x - parent.clientStart.x + this.box.right, scrolledPos.y - parent.clientStart.y + this.box.bottom }; parent.Update(box); } else { Box box { scrolledPos.x + this.box.left, scrolledPos.y + this.box.top, scrolledPos.x + this.box.right, scrolledPos.y + this.box.bottom}; parent.Update(box); } } SetPosition(x, y, w, h, true, modifyArea, updateScrollBars); clientResized = oldCW != clientSize.w || oldCH != clientSize.h || force; if(clientResized && this == rootWindow && nativeDecorations && rootWindow.windowHandle) windowResized = true; if(display && rootWindow != this) Update(null); if(guiApp && guiApp.windowMoving) { if(guiApp.windowMoving.style.nonClient) guiApp.windowMoving.parent.SetMouseRangeToWindow(); else guiApp.windowMoving.parent.SetMouseRangeToClient(); } if(!positioned) { positioned = true; if(clientResized) { if(!thisOnly) { // Buttons bitmap resources crash if we do this while switching mode if(!guiApp || !guiApp.modeSwitching) UpdateNonClient(); // Process Anchored Children if(processAnchors) { int x,y,w,h; for(child = children.first; child; child = child.next) { if(child.created && ((child.stateAnchor.left.type != offset || child.stateAnchor.top.type != offset || child.stateAnchor.right.type != none || child.stateAnchor.bottom.type != none) || child.state == maximized || child.state == minimized)) { child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h); // child.Position(x, y, w, h, false, true, true, true, false); // This must be true cuz otherwise we're gonna miss everything since we SetPosition recursively already child.Position(x, y, w, h, true, true, true, true, false, true /*false*/); } } } } // Is this gonna cause other problems? Commented out for the FileDialog end bevel bug //if(updateScrollBars) if(created) OnResize(clientSize.w, clientSize.h); } if((clientResized || windowMoved) && created) OnPosition(position.x, position.y, clientSize.w, clientSize.h); /* if(guiApp.interimWindow && guiApp.interimWindow.master.rootWindow == this) { Window master = guiApp.interimWindow.master; master.OnPosition(master.position.x, master.position.y, master.clientSize.w, master.clientSize.h); } */ if(rootWindow == this && !is3D) { /*if(style.interim) { x -= guiApp.desktop.absPosition.x; y -= guiApp.desktop.absPosition.y; }*/ //guiApp.Log("Position %s\n", caption); if(windowHandle) { if(windowResized || windowMoved) if(display && !display.flags.memBackBuffer && changeRootWindow) guiApp.interfaceDriver.PositionRootWindow(this, x, y, w, h, windowMoved, windowResized); //realResized); if( #if !defined(__EMSCRIPTEN__) !guiApp.fullScreenMode && #endif this != guiApp.desktop && (windowResized || windowMoved)) for(child = parent.children.first; child && child != this; child = child.next) if(child.rootWindow) guiApp.interfaceDriver.UpdateRootWindow(child.rootWindow); } if(display) { if(windowMoved || windowResized) { display.Lock(true /*false*/); } if(windowMoved) display.Position(absPosition.x, absPosition.y); //display.Position(absPosition.x + clientStart.x, absPosition.y + clientStart.y); if(windowResized) { // result = realResized ? display.Resize(size.w, size.h) : true; if(nativeDecorations && rootWindow.windowHandle) { int w = clientSize.w, h = clientSize.h; if(hasMenuBar) h += skinMenuHeight; if(hasStatusBar) h += statusBarHeight; if(sbv && sbv.visible) w += sbv.size.w; if(sbh && sbh.visible) h += sbh.size.h; result = manageDisplay ? display.Resize(w, h) : true; } else result = manageDisplay ? display.Resize(size.w, size.h) : true; resized = true; Update(null); } else if(clientResized) Update(clientArea); // --- Major Slow Down / Fix OpenGL Resizing Main Window Lag /* if(!guiApp.fullScreenMode && !guiApp.modeSwitching && this == rootWindow) UpdateDisplay(); */ if(windowMoved || windowResized) { display.Unlock(); } } if(guiApp.driver && !guiApp.modeSwitching && changeRootWindow && windowHandle) { if(windowResized || windowMoved) if(!display || display.flags.memBackBuffer) guiApp.interfaceDriver.PositionRootWindow(this, x, y, w, h, windowMoved, windowResized); guiApp.interfaceDriver.UpdateRootWindow(this); } for(child = children.first; child; child = child.next) { if(child.is3D && child.created) { // Copy Display Content child.display.displaySystem = display.displaySystem; child.display.window = display.window; child.display.current = display.current; child.display.width = display.width; child.display.height = display.height; child.display.driverData = display.driverData; #if !defined(__EMSCRIPTEN__) child.display.mutex = null; #endif } } } else result = true; positioned = false; } return result; } void UpdateScrollBars(bool flag, bool fullThing) { int rvw, rvh; bool resizeH = false, resizeV = false; bool scrolled = false; rvw = (activeChild && activeChild.state == maximized) ? 0 : reqScrollArea.w; rvh = (activeChild && activeChild.state == maximized) ? 0 : reqScrollArea.h; if(destroyed) return; if(guiApp.currentSkin) { MinMaxValue cw = 0, ch = 0; bool sbvVisible = false, sbhVisible = false; int rangeH = 0, rangeV = 0; int positionH = 0, positionV; // First get client area with no respect to scroll bars if(flag) { SetWindowArea( &clientStart.x, &clientStart.y, &size.w, &size.h, &cw, &ch); if(scrollFlags.dontHide) { if(sbv) cw -= guiApp.currentSkin.VerticalSBW(); if(sbh) ch -= guiApp.currentSkin.HorizontalSBH(); // Update the scrollbar visibility if(sbh) { sbh.seen = cw; sbh.total = rvw; rangeH = sbh.range; sbh.disabled = rangeH <= 1; if(sbh.style.hidden) { resizeH = true; } } if(sbv) { sbv.seen = ch; sbv.total = rvh; rangeV = sbv.range; sbv.disabled = rangeV <= 1; if(sbv.style.hidden) { resizeV = true; } } } else { int oldHRange = sbh ? sbh.range : 0; int oldVRange = sbv ? sbv.range : 0; // Then start off with horizontal scrollbar range if(sbh) { positionH = sbh.thumbPosition; /* sbh.seen = cw; sbh.total = rvw; */ SBSetSeen(sbh, cw); SBSetTotal(sbh, rvw); rangeH = sbh.range; if(rangeH > 1) ch -= guiApp.currentSkin.HorizontalSBH(); } // Do the same for vertical scrollbar if(sbv) { positionV = sbv.thumbPosition; /* sbv.seen = ch; sbv.total = rvh; */ SBSetSeen(sbv, ch); SBSetTotal(sbv, rvh); rangeV = sbv.range; if(rangeV > 1) { cw -= guiApp.currentSkin.VerticalSBW(); // Maybe we need to set the range on the horizontal scrollbar again if(sbh) { /* sbh.seen = cw; sbh.total = rvw; */ SBSetSeen(sbh, cw); SBSetTotal(sbh, rvw); //sbh.Action(setRange, positionH, 0); if(rangeH <= 1 && sbh.range > 1) { ch -= guiApp.currentSkin.HorizontalSBH(); /* sbv.seen = ch; sbv.total = rvh; */ SBSetSeen(sbv, ch); SBSetTotal(sbv, rvh); rangeV = sbv.range; //sbv.Action(setRange, positionV, 0); } rangeH = sbh.range; } } if(sbh && sbh.range != oldHRange) sbh.Action(setRange, positionH, 0); if(sbv && sbv.range != oldVRange) sbv.Action(setRange, positionV, 0); } // Update the scrollbar visibility if(!scrollFlags.dontHide) { if(sbh && ((rangeH <= 1 && !sbh.style.hidden) || (rangeH > 1 && sbh.style.hidden))) { resizeH = true; } if(sbv && ((rangeV <= 1 && !sbv.style.hidden) || (rangeV > 1 && sbv.style.hidden))) { resizeV = true; } } } if(guiApp.currentSkin) { clientSize.w = cw; clientSize.h = ch; } if(resizeH) sbhVisible = sbh.style.hidden ? true : false; if(resizeV) sbvVisible = sbv.style.hidden ? true : false; // Do our resize here if(flag && (resizeH || resizeV) && fullThing) { Position(position.x, position.y, size.w, size.h, false, true, false, false, false, false); if(!positioned) { positioned = true; OnResize(clientSize.w, clientSize.h); positioned = false; } } if(resizeH && sbh) sbh.visible = sbhVisible; if(resizeV && sbv) sbv.visible = sbvVisible; } scrollArea.w = Max(clientSize.w, reqScrollArea.w); scrollArea.h = Max(clientSize.h, reqScrollArea.h); if(sbh) sbh.pageStep = clientSize.w; if(sbv) sbv.pageStep = clientSize.h; // Notify doesn't handle setRange anymore... process it here if(sbh) { int positionH = sbh.thumbPosition; if(scroll.x != positionH) { OnHScroll(setRange, positionH, 0); scrolled = true; } if(guiApp.textMode) SNAPDOWN(positionH, textCellW); scroll.x = positionH; } else { int x = scroll.x; int range; int seen = clientSize.w, total = reqScrollArea.w; seen = Max(1,seen); if(scrollFlags.snapX) SNAPDOWN(seen, sbStep.x); if(!total) total = seen; range = total - seen + 1; range = Max(range, 1); if(x < 0) x = 0; if(x >= range) x = range - 1; if(scrollFlags.snapX) SNAPUP(x, sbStep.x); if(scroll.x != x) { OnHScroll(setRange, x, 0); } if(guiApp.textMode) { SNAPDOWN(x, textCellW); } scroll.x = x; } if(sbv) { int positionV = sbv.thumbPosition; if(scroll.y != positionV) { OnVScroll(setRange, positionV, 0); scrolled = true; } if(guiApp.textMode) SNAPDOWN(positionV, textCellH); scroll.y = positionV; } else { int y = scroll.y; int range; int seen = clientSize.h, total = reqScrollArea.h; seen = Max(1,seen); if(scrollFlags.snapY) SNAPDOWN(seen, sbStep.y); if(!total) total = seen; range = total - seen + 1; range = Max(range, 1); if(y < 0) y = 0; if(y >= range) y = range - 1; if(scrollFlags.snapY) SNAPUP(y, sbStep.y); if(scroll.y != y) { OnVScroll(setRange, y, 0); } if(guiApp.textMode) { SNAPDOWN(y, textCellH); } scroll.y = y; } /* if(scrolled || (resizeH || resizeV)) // This ensures children anchored to bottom/right gets repositioned correctly { Window child; for(child = children.first; child; child = child.next) { if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert)) { int x,y,w,h; child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h); child.Position(x, y, w, h, false, true, false, true, false, false); } } } */ } // Process Scrollbars if(sbh) // && !sbh.style.hidden { if(!sbh.anchored) sbh.Move(clientStart.x, clientStart.y + clientSize.h, clientSize.w,0); // Need to set the range again (should improve...) since the scrollbars didn't have // the right size when UpdateScrollArea set the range on it if(flag) { sbh.seen = clientSize.w; sbh.total = rvw; } } if(sbv) // && !sbv.state.hidden { if(!sbv.anchored) sbv.Move(clientStart.x + clientSize.w, clientStart.y, 0, clientSize.h); // Need to set the range again (should improve...) since the scrollbars didn't have // the right size when UpdateScrollArea set the range on it if(flag) { sbv.seen = clientSize.h; sbv.total = rvh; } } // TESTING THIS LOWER if(scrolled || (resizeH || resizeV)) // This ensures children anchored to bottom/right gets repositioned correctly { Window child; for(child = children.first; child; child = child.next) { if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert)) { int x,y,w,h; child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h); child.Position(x, y, w, h, false, true, false, true, false, false); } } } } bool MaximizeButtonClicked(Button button, int x, int y, Modifiers mods) { SetState(maximized, false, mods); return false; } bool RestoreButtonClicked(Button button, int x, int y, Modifiers mods) { SetState(normal, false, mods); return false; } bool MinimizeButtonClicked(Button button, int x, int y, Modifiers mods) { SetState(minimized, false, mods); parent.CycleChildren(false, true, false, true); return false; } void ScrollBarNotification(ScrollBar control, ScrollBarAction action, int position, Key keyFlags) { Window child; // Scroll bar notifications if(action != setRange) { bool changed = false; if(control == sbh) { if(scroll.x != position) { OnHScroll(action, position, keyFlags); changed = true; } if(guiApp.textMode) { SNAPDOWN(position, textCellW); } scroll.x = position; } else { if(scroll.y != position) { OnVScroll(action, position, keyFlags); changed = true; } if(guiApp.textMode) { SNAPDOWN(position, textCellH); } scroll.y = position; } if(changed) { bool childMove = false; for(child = children.first; child; child = child.next) { if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert)) { int x,y,w,h; child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h); child.Position(x, y, w, h, false, true, false, true, false, false); childMove = true; } } // Testing this patch out to solve MDI workspace redraw bugs // We were already supposed to be updating parent's affected area in Position() but it doesn't seem to be working // Scroll offsets to blame? if(childMove) Update(null); } UpdateCaret(false, false); } else { // Testing this patch out to solve MDI workspace redraw bugs for(child = children.first; child; child = child.next) { if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert)) { Update(null); break; } } } } Window GetParentMenuBar() { Window menuBarParent; if(formDesigner) return null; for(menuBarParent = this ? parent : null; menuBarParent; menuBarParent = menuBarParent.parent) { if(menuBarParent.menuBar) return menuBarParent.menuBar; if(menuBarParent && !menuBarParent.isActiveClient) return null; } return null; } void CreateSystemChildren(void) { Window parent = this; bool scrollBarChanged = false; bool hasClose = false, hasMaxMin = false; Point scroll = this.scroll; if(state == maximized) { parent = GetParentMenuBar(); if(!parent) parent = this; } if(parent) { if(style.hasClose) hasClose = true; if(style.hasMaximize || style.hasMinimize) { hasClose = true; hasMaxMin = true; } } if(sysButtons[2] && (!hasClose || sysButtons[2].parent != parent)) { sysButtons[2].Destroy(0); sysButtons[2] = null; } if(sysButtons[1] && (!hasMaxMin || sysButtons[1].parent != parent)) { sysButtons[1].Destroy(0); sysButtons[1] = null; } if(sysButtons[0] && (!hasMaxMin || sysButtons[0].parent != parent)) { sysButtons[0].Destroy(0); sysButtons[0] = null; } //return; if(hasClose && parent) { if(!sysButtons[2]) { sysButtons[2] = Button { parent, master = this, inactive = true, nonClient = true, visible = false; bool NotifyClicked(Button button, int x, int y, Modifiers mods) { Destroy(0); return true; } }; if(this.parent == guiApp.desktop) sysButtons[2].hotKey = altF4; else if(style.isActiveClient) sysButtons[2].hotKey = ctrlF4; sysButtons[2].Create(); } sysButtons[2].symbol = 'X'; sysButtons[2].disabled = !style.hasClose; } if(hasMaxMin && parent) { //SkinBitmap skin; unichar symbol; bool (* method)(Window window, Button button, int x, int y, Modifiers mods); if(state == maximized) { //skin = restore; method = RestoreButtonClicked; symbol = '\x12'; } else { //skin = maximize; method = MaximizeButtonClicked; symbol = '\x18'; } if(!sysButtons[1]) { sysButtons[1] = Button { parent, master = this, hotKey = altEnter, inactive = true, nonClient = true, visible = false }; sysButtons[1].Create(); } sysButtons[1].NotifyClicked = method; sysButtons[1].symbol = symbol; sysButtons[1].disabled = !style.hasMaximize; } if(hasMaxMin && parent) { //SkinBitmap skin; unichar symbol; bool (* method)(Window window, Button button, int x, int y, Modifiers mods); if (state == minimized) { //skin = restore; method = RestoreButtonClicked; symbol = '\x12'; } else { //skin = minimize; method = MinimizeButtonClicked; symbol = '\x19'; } if(!sysButtons[0]) { sysButtons[0] = Button { parent, master = this, hotKey = altM, inactive = true, nonClient = true, visible = false }; sysButtons[0].Create(); } sysButtons[0].NotifyClicked = method; sysButtons[0].symbol = symbol; sysButtons[0].disabled = !style.hasMinimize; } // Create the scrollbars if(style.hasHorzScroll && !sbh) { sbh = ScrollBar { this, direction = horizontal, windowOwned = true, inactive = true, nonClient = true, snap = scrollFlags.snapX, NotifyScrolling = ScrollBarNotification }; sbh.Create(); scrollBarChanged = true; } else if(sbh && !style.hasHorzScroll) { sbh.Destroy(0); sbh = null; } if(style.hasVertScroll && !sbv) { sbv = ScrollBar { this, direction = vertical, windowOwned = true, inactive = true, nonClient = true, snap = scrollFlags.snapY, NotifyScrolling = ScrollBarNotification }; sbv.Create(); scrollBarChanged = true; } else if(sbv && !style.hasVertScroll) { sbv.Destroy(0); sbv = null; } if(scrollBarChanged) { SetScrollLineStep(sbStep.x, sbStep.y); UpdateScrollBars(true, true); } UpdateNonClient(); if(scrollBarChanged) { if(sbh) sbh.thumbPosition = scroll.x; if(sbv) sbv.thumbPosition = scroll.y; } } void UpdateCaption(void) { if(rootWindow == this) { char caption[2048]; FigureCaption(caption); if(guiApp.interfaceDriver) guiApp.interfaceDriver.SetRootWindowCaption(this, caption); } UpdateDecorations(); if(parent) { if(parent.activeClient == this) // Added this last check { if(parent.rootWindow == parent) { char caption[2048]; parent.FigureCaption(caption); if(guiApp.interfaceDriver) guiApp.interfaceDriver.SetRootWindowCaption(parent, caption); } else parent.UpdateCaption(); } parent.UpdateDecorations(); } } void UpdateActiveDocument(Window previous) { Window activeClient = this.activeClient; Window activeChild = this.activeChild; if(menuBar) { UpdateCaption(); if(!destroyed) { if(activeClient) activeClient.CreateSystemChildren(); if(previous) previous.CreateSystemChildren(); } } if(menu) { MenuItem item; //bool disabled; if(menu) menu.Clean(this); // Build window list if(activeClient) { Menu windowMenu = menu.FindMenu("Window"); if(windowMenu) { OldLink cycle; int id; for(id = 0, cycle = activeClient.cycle; cycle && id<10;) { Window document = cycle.data; if(!document.style.nonClient && document.style.isActiveClient && document.visible) { char name[2048], caption[2048]; document.FigureCaption(caption); sprintf(name, "%d %s", id+1, caption); windowMenu.AddDynamic(MenuItem { copyText = true, text = name, hotKey = Key { k1 + id }, id = id++, NotifySelect = MenuWindowSelectWindow }, this, false); } cycle = cycle.next; if(activeClient.cycle == cycle) break; } } } if((!previous && activeClient) || !activeClient) { /*if(!activeClient) disabled = true; else disabled = false;*/ item = menu.FindItem(MenuWindowCloseAll, 0); if(item) item.disabled = false; item = menu.FindItem(MenuWindowNext, 0); if(item) item.disabled = false; item = menu.FindItem(MenuWindowPrevious, 0); if(item) item.disabled = false; item = menu.FindItem(MenuWindowCascade, 0); if(item) item.disabled = false; item = menu.FindItem(MenuWindowTileHorz, 0); if(item) item.disabled = false; item = menu.FindItem(MenuWindowTileVert, 0); if(item) item.disabled = false; item = menu.FindItem(MenuWindowArrangeIcons, 0); if(item) item.disabled = false; item = menu.FindItem(MenuWindowWindows, 0); if(item) item.disabled = false; } item = menu.FindItem(MenuFileClose, 0); if(item) item.disabled = !activeClient || !activeClient.style.hasClose; item = menu.FindItem(MenuFileSaveAll, 0); if(item) item.disabled = numDocuments < 1; if(activeClient && activeClient.menu && activeClient.state != minimized) { if(mergeMenus) { //activeClient.menu.Clean(activeClient); menu.Merge(activeClient.menu, true, activeClient); } } if(activeChild && activeChild != activeClient && activeChild.menu && activeChild.state != minimized) { if(mergeMenus) menu.Merge(activeChild.menu, true, activeChild); } } // This is called again for a child window change, with same active client OnActivateClient(activeClient, previous); if(!menuBar && !((BorderBits)borderStyle).fixed && parent && parent.activeClient == this) parent.UpdateActiveDocument(null); } void _ShowDecorations(Box box, bool post) { if(rootWindow == this && nativeDecorations && !is3D) return; if(visible && this != guiApp.desktop) { Surface surface = RedrawFull(box); if(surface) { char caption[2048]; FigureCaption(caption); if(post) ShowDecorations(captionFont.font, surface, caption, active, //parent.activeClient == this guiApp.windowMoving == this); else PreShowDecorations(captionFont.font, surface, caption, active, //parent.activeClient == this guiApp.windowMoving == this); delete surface; } } } void UpdateExtent(Box refresh) { Surface surface = null; if(!manageDisplay) { OnRedraw(null);return; } _ShowDecorations(refresh, false); surface = Redraw(refresh); // Opaque background: just fill before EW_REDRAW (clear?) if(surface) { surface.SetBackground(background); surface.SetForeground(foreground); surface.DrawingChar(' '); if(this == rootWindow) { if(style.drawBehind || background.a) { int a = background.a; // Premultiply alpha for clear color surface.SetBackground({ (byte)a, { (byte)(a*background.color.r/255), (byte)(a*background.color.g/255), (byte)(a*background.color.b/255) } }); surface.Clear(colorBuffer); surface.SetBackground(background); } } else if(background.a) { #ifdef _DEBUG /* background.color = { (byte)GetRandom(0,255), (byte)GetRandom(0,255), (byte)GetRandom(0,255) }; surface.SetForeground((background.color.r > 128 || background.color.g > 128) ? black : white); */ #endif if(display.flags.alpha && background.a < 255 && background) { surface.Area(0,0,clientSize.w, clientSize.h); /*if(style.clearDepthBuffer) surface.Clear(depthBuffer);*/ } else if(/*style.clearDepthBuffer || */background.a) { int a = background.a; // surface.Clear((style.clearDepthBuffer ? depthBuffer : 0) | (background.a ? colorBuffer : 0)); // Premultiply alpha for clear color surface.SetBackground({ (byte)a, { (byte)(a*background.color.r/255), (byte)(a*background.color.g/255), (byte)(a*background.color.b/255) } }); surface.Clear(colorBuffer); surface.SetBackground(background); } } // Default Settings surface.TextFont(usedFont.font); surface.TextOpacity(false); surface.outlineColor = black; OnRedraw(surface); // Draw the caret ... if(!disabled && this == guiApp.caretOwner && guiApp.caretEnabled /*&& !guiApp.interimWindow*/ && !guiApp.currentSkin.textMode) { // surface.SetBackground(0xFFFFFF - background.color); surface.SetBackground(~background.color); surface.Area( caretPos.x - scroll.x + 1, caretPos.y - scroll.y, caretPos.x - scroll.x + 2, caretPos.y - scroll.y + caretSize - 1); } delete surface; } } void DrawOverChildren(Box refresh) { Surface surface = Redraw(refresh); if(surface) { // Default Settings surface.DrawingChar(' '); surface.SetBackground(background); surface.SetForeground(foreground); surface.TextFont(usedFont.font); surface.TextOpacity(false); surface.outlineColor = black; OnDrawOverChildren(surface); delete surface; } _ShowDecorations(refresh, true); } void ComputeClipExtents(void) { Window child; Extent clipExtent { /*first = -1, last = -1, free = -1*/ }; clipExtent.Copy(this.clipExtent); for(child = children.last; child; child = child.prev) { if(!child.style.hidden && child.created && !child.is3D && child.rootWindow) { bool opaque = child.IsOpaque(); // TODO: acess background directly int dx = child.absPosition.x - absPosition.x, dy = child.absPosition.y - absPosition.y; child.clipExtent.Copy(clipExtent); child.clipExtent.Offset(-dx, -dy); child.clipExtent.IntersectBox(child.box); child.ComputeClipExtents(); if(opaque && !child.style.nonClient) { // Adjust the box for the parent: Box box { child.box.left + dx, child.box.top + dy, child.box.right + dx, child.box.bottom + dy }; clipExtent.ExcludeBox(box, rootWindow.tempExtents[0]); } } } // ??? Only do this for overlapped window or if parent has with clip children flag // Do this if window has clip children flag on (default false?) // this.clipExtent = clipExtent; clipExtent.Free(null); } void ComputeRenderAreaNonOpaque(Extent dirtyExtent, Extent overDirtyExtent, Extent backBufferUpdate) { Window child; int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y; if(rootWindow.nativeDecorations && rootWindow.windowHandle) { offsetX -= rootWindow.clientStart.x; offsetY -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0); } for(child = children.last; child; child = child.prev) { bool opaque = child.IsOpaque(); if(!child.style.hidden && child.created && !child.is3D && child.rootWindow) { if(!opaque) { // Adjust renderArea to the root window level Extent * renderArea = &rootWindow.tempExtents[3]; int offsetX = child.absPosition.x - rootWindow.absPosition.x; int offsetY = child.absPosition.y - rootWindow.absPosition.y; if(child.rootWindow.nativeDecorations && rootWindow.windowHandle) { offsetX -= child.rootWindow.clientStart.x; offsetY -= child.rootWindow.clientStart.y - (child.rootWindow.hasMenuBar ? skinMenuHeight : 0); } /* Extent childRenderArea; if(backBufferUpdate != null) { childRenderArea.Copy(backBufferUpdate); childRenderArea.Offset(-offsetX, -offsetY); } else childRenderArea.Copy(child.dirtyArea); // Add extent forced by transparency to the dirty area, adjusting dirty extent to the window renderArea.Copy(dirtyExtent); renderArea.Offset(-offsetX, -offsetY); childRenderArea.Union(renderArea); renderArea.Free(); // Intersect with the clip extent childRenderArea.Intersection(child.clipExtent); */ renderArea->Copy(child.dirtyArea /*childRenderArea*/); // This intersection with child clip extent was missing and causing #708 (Installer components list scrolling bug): renderArea->Intersection(child.clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]); renderArea->Offset(offsetX, offsetY); dirtyExtent.Union(renderArea, rootWindow.tempExtents[0]); // overDirtyExtent.Union(renderArea); renderArea->Empty(); // childRenderArea.Free(); //child.ComputeRenderAreaNonOpaque(dirtyExtent, overDirtyExtent, backBufferUpdate); } } } for(child = children.last; child; child = child.prev) { if(!child.style.hidden && child.created && !child.is3D && child.rootWindow) { child.ComputeRenderAreaNonOpaque(dirtyExtent, overDirtyExtent, backBufferUpdate); } } } void ComputeRenderArea(Extent dirtyExtent, Extent overDirtyExtent, Extent backBufferUpdate) { bool opaque = IsOpaque(); Extent * dirtyExtentWindow = &rootWindow.tempExtents[1]; Window child; int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y; if(rootWindow.nativeDecorations && rootWindow.windowHandle) { offsetX -= rootWindow.clientStart.x; offsetY -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0); } #if 0 for(child = children.last; child; child = child.prev) { //child.ComputeRenderAreaNonOpaque(dirtyExtent, overDirtyExtent, backBufferUpdate); /* ColorAlpha background = *(ColorAlpha *)&child.background; bool opaque = child.IsOpaque(); if(!child.style.hidden && child.created && !child.is3D && child.rootWindow) { if(!opaque) { int offsetX = child.absPosition.x - rootWindow.absPosition.x, offsetY = child.absPosition.y - rootWindow.absPosition.y; // Adjust renderArea to the root window level Extent renderArea; renderArea.Copy(child.dirtyArea); renderArea.Offset(offsetX, offsetY); dirtyExtent.Union(renderArea); overDirtyExtent.Union(renderArea); renderArea.Free(); } }*/ } #endif for(child = children.last; child; child = child.prev) { if(!child.style.hidden && child.created && !child.is3D && child.rootWindow) { child.ComputeRenderArea(dirtyExtent, overDirtyExtent, backBufferUpdate); } } if(backBufferUpdate != null) { renderArea.Copy(backBufferUpdate); renderArea.Offset(-offsetX, -offsetY); overRenderArea.Copy(backBufferUpdate); overRenderArea.Offset(-offsetX, -offsetY); } else { renderArea.Copy(dirtyArea); overRenderArea.Copy(dirtyArea); } // Add extent forced by transparency to the dirty area, adjusting dirty extent to the window dirtyExtentWindow->Copy(dirtyExtent); dirtyExtentWindow->Offset(-offsetX, -offsetY); renderArea.Union(dirtyExtentWindow, rootWindow.tempExtents[0]); dirtyExtentWindow->Empty(); // Intersect with the clip extent renderArea.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]); /* if(renderArea.count > 10) { BoxItem extentBox; printf("\nToo many extents (%d):\n", renderArea.count); //extent.UnionBox({ 112, 6, 304, 7 }, rootWindow.tempExtents[0]); //extent.UnionBox({ 112, 8, 304, 17 }, rootWindow.tempExtents[0]); //printf("Test\n"); { int c; for(c = 0; c<10; c++) { Extent extent { }; FASTLIST_LOOP(renderArea, extentBox) { extent.UnionBox(extentBox.box, rootWindow.tempExtents[0]); } renderArea.Copy(extent); FASTLIST_LOOP(renderArea, extentBox) { #ifdef _DEBUG printf("(%d, %d) - (%d, %d)\n", extentBox.box.left, extentBox.box.top, extentBox.box.right, extentBox.box.bottom); #endif } printf("\nNow %d\n", renderArea.count); } } } */ // WHY WAS THIS COMMENTED ?? // Add extent forced by DrawOverChildren to the dirty area, adjusting dirty extent to the window dirtyExtentWindow->Copy(overDirtyExtent); dirtyExtentWindow->Offset(-offsetX, -offsetY); overRenderArea.Union(dirtyExtentWindow, rootWindow.tempExtents[0]); dirtyExtentWindow->Empty(); // Intersect with the clip extent overRenderArea.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]); if(opaque) { // Scrolling if(scrollExtent.count) { // Subtract render extent from scrolling extent scrollExtent.Exclusion(renderArea, rootWindow.tempExtents[0]); if(backBufferUpdate == null) { Extent * dirty = &rootWindow.tempExtents[3]; BoxItem scrollBox; // Intersect scrolling extent with clip extent scrollExtent.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]); // offset this scroll to be at the root window level scrollExtent.Offset(offsetX, offsetY); // Add area that was scrolled to the dirty extents of the back buffer rootWindow.dirtyBack.Union(scrollExtent, rootWindow.tempExtents[0]); dirty->Empty(); // Will need scrolledArea.x & scrolledArea.y to support multiple scrolls for(scrollBox = (BoxItem)scrollExtent.first; scrollBox; scrollBox = (BoxItem)scrollBox.next) display.Scroll(scrollBox.box, scrolledArea.x, scrolledArea.y, dirty); scrolledArea.x = 0; scrolledArea.y = 0; scrollExtent.Empty(); // Add the exposed extent to the window render area dirty->Offset(-offsetX, -offsetY); renderArea.Union(dirty, rootWindow.tempExtents[0]); dirty->Empty(); } } // Subtract the window's box from the transparency forced extent dirtyExtent.ExcludeBox({box.left + offsetX, box.top + offsetY, box.right + offsetX, box.bottom + offsetY }, rootWindow.tempExtents[0]); } /*else { Extent renderArea; renderArea.Copy(this.renderArea); renderArea.Offset(offsetX, offsetY); dirtyExtent.Union(renderArea); renderArea.Free(); }*/ { Extent renderArea { }; renderArea.Copy(overRenderArea); renderArea.Offset(offsetX, offsetY); overDirtyExtent.Union(renderArea, rootWindow.tempExtents[0]); renderArea.Empty(); } if(backBufferUpdate != null) { // Remove render area from dirty area dirtyArea.Exclusion(renderArea, rootWindow.tempExtents[0]); dirtyArea.Exclusion(overRenderArea, rootWindow.tempExtents[0]); } else dirtyArea.Empty(); clipExtent.Empty(); /* // Remove the window render area from the dirty extents of the back buffer rootWindow.dirtyBack.Exclusion(renderArea); */ } void Render(Extent updateExtent) { BoxItem extentBox; Window child; Window rootWindow = this.rootWindow; int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y; if(rootWindow.nativeDecorations && rootWindow.windowHandle) { offsetX -= rootWindow.clientStart.x; offsetY -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0); } if(rootWindow.fullRender) { UpdateExtent(box); dirtyArea.Empty(); } else { #ifdef _DEBUG /* background = Color { (byte)GetRandom(0,255), (byte)GetRandom(0,255), (byte)GetRandom(0,255) }; foreground = (background.color.r > 128 || background.color.g > 128) ? black : white; */ #endif #ifdef _DEBUG /*if(renderArea.count) printf("\n\nRendering %s (%x):\n------------------------------------------\n", _class.name, this);*/ #endif for(extentBox = (BoxItem)renderArea.first; extentBox; extentBox = (BoxItem)extentBox.next) { Box box = extentBox.box; #ifdef _DEBUG /*printf("(%d, %d) - (%d, %d)\n", extentBox.box.left, extentBox.box.top, extentBox.box.right, extentBox.box.bottom);*/ #endif UpdateExtent(box); box.left += offsetX; box.top += offsetY; box.right += offsetX; box.bottom += offsetY; if(updateExtent != null) updateExtent.UnionBox(box, rootWindow.tempExtents[0]); } } for(child = children.first; child; child = child.next) if(!child.style.hidden && child.created && !child.is3D && child.rootWindow && !child.nonClient) child.Render(updateExtent); if(rootWindow.fullRender) DrawOverChildren(box); else { // TO DO: There's an issue about draw over children... // TO DO: Don't wanna go through this if method isn't used for(extentBox = (BoxItem)overRenderArea.first; extentBox; extentBox = (BoxItem)extentBox.next) //FASTLIST_LOOP(/*renderArea */overRenderArea, extentBox) { Box box = extentBox.box; DrawOverChildren(box); box.left += offsetX; box.top += offsetY; box.right += offsetX; box.bottom += offsetY; if(updateExtent != null) updateExtent.UnionBox(box, rootWindow.tempExtents[0]); } } for(child = children.first; child; child = child.next) if(!child.style.hidden && child.created && !child.is3D && child.rootWindow && child.nonClient) child.Render(updateExtent); renderArea.Empty(); overRenderArea.Empty(); } public void UpdateDisplay(void) { if(!manageDisplay) { OnRedraw(null);return; } if(rootWindow && this != rootWindow) rootWindow.UpdateDisplay(); else if(display) { Extent dirtyExtent { /*first = -1, last = -1, free = -1*/ }; // Extent that needs to be forced due to transparency Extent overExtent { /*first = -1, last = -1, free = -1*/ }; // Extent that forced for DrawOverChildren BoxItem extentBox; dirtyExtent.Clear(); overExtent.Clear(); clipExtent.AddBox(box); display.Lock(true); display.StartUpdate(); if(!rootWindow.fullRender) { ComputeClipExtents(); ComputeRenderAreaNonOpaque(dirtyExtent, overExtent, null); ComputeRenderArea(dirtyExtent, overExtent, null); } else clipExtent.Free(null); dirtyExtent.Free(null); overExtent.Free(null); if(display.flags.flipping) { Render(null); display.Update(null); } else { Extent updateExtent { /*first = -1, last = -1, free = -1*/ }; // Extent that needs to be updated updateExtent.Clear(); Render(updateExtent); if(fullRender) updateExtent.UnionBox(this.box, tempExtents[0]); #ifdef _DEBUG //printf("\n\nUpdate:\n------------------------------------------\n"); #endif //FASTLIST_LOOP(updateExtent, extentBox) for(extentBox = (BoxItem)updateExtent.first; extentBox; extentBox = (BoxItem)extentBox.next) { #ifdef _DEBUG /*printf("Updating (%d, %d) - (%d, %d)\n", extentBox.box.left, extentBox.box.top, extentBox.box.right, extentBox.box.bottom);*/ #endif display.Update(extentBox.box); } updateExtent.Free(null); } display.EndUpdate(); display.Unlock(); dirtyBack.Empty(); dirty = false; resized = false; } } void UpdateBackDisplay(Box box) { if(display) { Extent dirtyExtent; Extent overExtent; Extent intersection { /*first = -1, last = -1, free = -1*/ }; //printf("UpdateBackDisplay going through!\n"); display.StartUpdate(); if(resized) { intersection.Copy(dirtyBack); intersection.IntersectBox(box); dirtyExtent.Clear(); overExtent.Clear(); clipExtent.AddBox(box); if(!rootWindow.fullRender) { ComputeClipExtents(); ComputeRenderArea(dirtyExtent, overExtent, intersection); } else clipExtent.Free(null); intersection.Free(null); dirtyExtent.Free(null); overExtent.Free(null); Render(null); } if(display.flags.flipping) display.Update(null); else { rootWindow.display.Update(box); } display.EndUpdate(); if(resized) { dirtyBack.ExcludeBox(box, rootWindow.tempExtents[0]); if(dirtyBack.count > MAX_DIRTY_BACK) { BoxItem extentBox, next; BoxItem first = (BoxItem)ACCESS_ITEM(dirtyBack, dirtyBack.first); for(extentBox = (BoxItem)dirtyBack.first; extentBox; extentBox = next) { next = (BoxItem)extentBox.next; if(extentBox != first) { if(extentBox.box.left < first.box.left) first.box.left = extentBox.box.left; if(extentBox.box.top < first.box.top) first.box.top = extentBox.box.top; if(extentBox.box.right > first.box.right) first.box.right = extentBox.box.right; if(extentBox.box.bottom > first.box.bottom) first.box.bottom = extentBox.box.bottom; dirtyBack.Delete(extentBox); } } } resized = false; } } } // --- Window positioning --- // --- Window identification --- // Returns window at position "Position" Window GetAtPosition(int x, int y, bool clickThru, bool acceptDisabled, Window last) { Window child, result = null; Box box = this.box; box.left += absPosition.x; box.right += absPosition.x; box.top += absPosition.y; box.bottom += absPosition.y; if(!destroyed && visible && (acceptDisabled || !disabled)) { int lx = x - absPosition.x; int ly = y - absPosition.y; if(IsInside(lx, ly)) // if(box.IsPointInside(Point{x, y})) { if(!clickThru || !style.clickThrough) result = (this == last) ? null : this; // If the window is disabled, stop looking in children (for acceptDisabled mode) if(!disabled) { bool isD = (last && last != this && last.IsDescendantOf(this)); // Fix for WSMS (#844) Window ancestor = null; if(isD) for(ancestor = last; ancestor && ancestor.parent != this; ancestor = ancestor.parent); for(child = (isD ? (last != ancestor ? ancestor : ancestor.previous) : children.last); child; child = child.prev) { if(child != statusBar && child.rootWindow == rootWindow) { Window childResult = child.GetAtPosition(x, y, clickThru, acceptDisabled, last); if(childResult) return childResult; } } if(clickThru) { for(child = (isD ? (last != ancestor ? ancestor : ancestor.previous) : children.last); child; child = child.prev) { if(child != statusBar && child.rootWindow == rootWindow) { Window childResult = child.GetAtPosition(x, y, false, acceptDisabled, last); if(childResult) return childResult; } } } if(last && last != this && this.IsDescendantOf(last)) // Fix for installer lockup result = null; } } } return result; } Window FindModal(void) { Window modalWindow = this, check; Window check2 = null; for(check = this; check.master; check = check.master) { if(check.master.modalSlave && check.master.modalSlave.created && check != check.master.modalSlave) { modalWindow = check.master.modalSlave; check = modalWindow; } // TESTING THIS FOR DROPBOX... if(!rootWindow || !rootWindow.style.interim) { for(check2 = check; check2 /*.activeChild*/; check2 = check2.activeChild) { if(check2.modalSlave && check2.modalSlave.created) { modalWindow = check2.modalSlave; break; } } } } /* if(modalWindow == this) { for(check = this; check.activeChild; check = check.activeChild) { if(check.modalSlave) { modalWindow = check.modalSlave; break; } } } */ for(; modalWindow.modalSlave && modalWindow.modalSlave.created; modalWindow = modalWindow.modalSlave); return (modalWindow == this || this == guiApp.interimWindow || IsDescendantOf(modalWindow)) ? null : modalWindow; } void StopMoving(void) { if(this == guiApp.windowMoving) { guiApp.windowMoving = null; UpdateDecorations(); SetMouseRange(null); if(rootWindow) { if(rootWindow.active) guiApp.interfaceDriver.StopMoving(rootWindow); } guiApp.windowCaptured.ReleaseCapture(); guiApp.resizeX = guiApp.resizeY = guiApp.resizeEndX = guiApp.resizeEndY = false; guiApp.windowIsResizing = false; } } void SelectMouseCursor(void) { int x,y; Window mouseWindow; Window modalWindow; Window cursorWindow = null; bool rx, ry, rex, rey; guiApp.desktop.GetMousePosition(&x, &y); mouseWindow = rootWindow ? rootWindow.GetAtPosition(x,y, true, false, null) : null; if((guiApp.windowMoving && !guiApp.windowIsResizing) || guiApp.windowScrolling) guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[moving]); else if(mouseWindow) { modalWindow = mouseWindow.FindModal(); x -= mouseWindow.absPosition.x; y -= mouseWindow.absPosition.y; if(guiApp.windowIsResizing) { rex = guiApp.resizeEndX; rey = guiApp.resizeEndY; rx = guiApp.resizeX; ry = guiApp.resizeY; if((rex && rey) || (rx && ry)) guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeNWSE]); else if((rex && ry) || (rx && rey)) guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeNESW]); else if((ry || rey) && (!rx && !rex)) guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeNS]); else if((rx || rex) && (!ry && !rey)) guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeWE]); } else if(!modalWindow && !guiApp.windowCaptured && mouseWindow.IsMouseResizing(x, y, mouseWindow.size.w, mouseWindow.size.h, &rx, &ry, &rex, &rey)) { if((rex && rey) || (rx && ry)) guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeNWSE]); else if((rex && ry) || (rx && rey)) guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeNESW]); else if((ry || rey) && (!rx && !rex)) guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeNS]); else if((rx || rex) && (!ry && !rey)) guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[sizeWE]); } else if(!guiApp.windowCaptured && !modalWindow && !guiApp.interimWindow) { if(!mouseWindow.clientArea.IsPointInside({x - mouseWindow.clientStart.x, y - mouseWindow.clientStart.y}) && mouseWindow.rootWindow != mouseWindow) cursorWindow = mouseWindow.parent; else cursorWindow = mouseWindow; } else if(!guiApp.interimWindow) cursorWindow = guiApp.windowCaptured; if(cursorWindow) { for(; !cursorWindow.cursor && !cursorWindow.style.nonClient && cursorWindow.rootWindow != cursorWindow; cursorWindow = cursorWindow.parent); guiApp.SetCurrentCursor(mouseWindow, cursorWindow.cursor ? cursorWindow.cursor : guiApp.systemCursors[arrow]); } else if(modalWindow) { guiApp.SetCurrentCursor(mouseWindow, guiApp.systemCursors[arrow]); } else if(guiApp.interimWindow) { if(guiApp.interimWindow.cursor) guiApp.SetCurrentCursor(mouseWindow, guiApp.interimWindow.cursor); else guiApp.SetCurrentCursor(mouseWindow, mouseWindow.cursor ? mouseWindow.cursor : guiApp.systemCursors[arrow]); } } } // --- State based input --- bool AcquireInputEx(bool state) { bool result; if(state) { guiApp.interfaceDriver.GetMousePosition(&guiApp.acquiredMouseX, &guiApp.acquiredMouseY); guiApp.interfaceDriver.SetMousePosition(clientSize.w/2 + absPosition.x, clientSize.h/2 + absPosition.y); } result = guiApp.interfaceDriver.AcquireInput(rootWindow, state); if(result) guiApp.acquiredWindow = state ? this : null; if(state && result) { SetMouseRangeToClient(); guiApp.interfaceDriver.SetMouseCursor(guiApp.acquiredWindow, (SystemCursor)-1); } else { FreeMouseRange(); SelectMouseCursor(); } if(!state) guiApp.interfaceDriver.SetMousePosition(guiApp.acquiredMouseX, guiApp.acquiredMouseY); return result; } // --- Window activation --- bool PropagateActive(bool active, Window previous, bool * goOnWithActivation, bool direct) { bool result = true; if(!parent || !parent.style.inactive) { Window parent = this.parent; /* if(rootWindow == this) Log(active ? "active\n" : "inactive\n"); */ if(active && requireRemaximize) { if(state == maximized) { property::state = normal; property::state = maximized; } requireRemaximize = false; } // Testing this here... if(!parent || parent == guiApp.desktop || parent.active) { this.active = active; } // TESTING THIS HERE UpdateDecorations(); if((result = OnActivate(active, previous, goOnWithActivation, direct) && *goOnWithActivation && master)) result = NotifyActivate(master, this, active, previous); else { this.active = !active; } if(result) { if(!parent || parent == guiApp.desktop || parent.active) { this.active = active; if(acquiredInput) AcquireInputEx(active); if(active && isEnabled) { if(caretSize) { if(guiApp.caretOwner) { Box extent { guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 1, guiApp.caretOwner.caretPos.y - guiApp.caretOwner.scroll.y + 1, guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 2, guiApp.caretOwner.caretPos.y - guiApp.caretOwner.scroll.y + guiApp.caretOwner.caretSize - 1 }; guiApp.caretOwner.Update(extent); } if(visible || !guiApp.caretOwner) guiApp.caretOwner = this; UpdateCaret(false, false); } } } else { this.active = false; if(acquiredInput) AcquireInputEx(active); } if(!active && guiApp.caretOwner == this) { UpdateCaret(false, true); guiApp.caretOwner = null; guiApp.interfaceDriver.SetCaret(0,0,0); guiApp.caretEnabled = false; } if(!style.interim) { if(!active && parent && parent.activeChild && parent.activeChild != this) if(!parent.activeChild.PropagateActive(false, previous, goOnWithActivation, true) || !*goOnWithActivation) { return false; } } if(!active && menuBar) { bool goOn; menuBar.OnActivate(false, null, &goOn, true); menuBar.NotifyActivate(menuBar.master, menuBar, false, null); } if(activeChild) { Window aChild = activeChild; incref aChild; if(!aChild.PropagateActive(active, previous, goOnWithActivation, false) || !*goOnWithActivation) { delete aChild; return false; } delete aChild; } } } return result; } void ConsequentialMouseMove(bool kbMoving) { if(rootWindow && !noConsequential) { if(kbMoving || !guiApp.windowMoving) { Modifiers mods {}; int x,y; if(rootWindow == guiApp.desktop || rootWindow.parent == guiApp.desktop) { if(guiApp.interfaceDriver) guiApp.interfaceDriver.GetMousePosition(&x, &y); if(guiApp.windowMoving || rootWindow.GetAtPosition(x, y, true, false, null)) rootWindow.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x, y, &mods, true, false); } } } } bool IsDescendantOf(Window ancestor) { Window window; for(window = this; window && window != ancestor; window = window.parent); return window == ancestor; } bool IsSlaveOf(Window master) { Window window; for(window = this; window && window != master; window = window.master); return window == master; } bool ActivateEx(bool active, bool activateParent, bool moveInactive, bool activateRoot, Window external, Window externalSwap) { bool result = true; if(this && !destroyed /*&& state != Hidden*/) { Window swap = externalSwap; incref this; if(parent) { if(!active) StopMoving(); if(activateParent && (parent.activeChild != this || (guiApp.interimWindow && !IsDescendantOf(guiApp.interimWindow))) && active && _isModal && parent != master && master) master.ActivateEx(true, true, false, activateRoot, external, externalSwap); if(active) { if(parent) { bool real = parent.activeChild != this; // TEST THIS: New activateParent check here!!! CAUSED MENUS NOT GOING AWAY if(!style.inactive && /*activateParent && */guiApp.interimWindow && !IsDescendantOf(guiApp.interimWindow) && !IsSlaveOf(guiApp.interimWindow)) { Window interimWindow = guiApp.interimWindow; while(interimWindow && interimWindow != this) { Window master = interimWindow.master; bool goOn = true; guiApp.interimWindow = null; if(guiApp.caretOwner) guiApp.caretOwner.UpdateCaret(false, false); incref interimWindow; if(!interimWindow.PropagateActive(false, this, &goOn, true)) { result = false; real = false; } delete interimWindow; interimWindow = (master && master.style.interim) ? master : null; } } if(style.interim) { guiApp.interimWindow = this; /*guiApp.interfaceDriver.SetCaret(0,0,0); guiApp.caretEnabled = false;*/ UpdateCaret(false, true); } if(real) { //bool acquireInput = false; bool maximize = parent.activeChild && parent.activeChild.state == maximized && parent != guiApp.desktop; if(!style.inactive) // (!style.isRemote || parent.active || parent.style.hidden)) { if(!style.interim) { if(!swap && parent) swap = parent.activeChild; if(swap && swap.destroyed) swap = null; if(swap && swap != this) { bool goOn = true; if(!swap.PropagateActive(false, this, &goOn, true)) swap = parent.activeChild; if(!goOn) { delete this; return false; } } else swap = null; } if(!parent || parent.activeChild != this || style.interim) { bool goOn = true; result = PropagateActive(true, swap, &goOn, true); if(!result && !goOn) { delete this; return false; } //acquireInput = true; } } if(style.hasMaximize && parent != guiApp.desktop) { if(maximize) SetState(maximized, false, 0); else if(state != maximized) { Window child; for(child = parent.children.first; child; child = child.next) { if(this != child && child.state == maximized) child.SetState(normal, false, 0); } } } } if(result) { if(!style.inactive && !style.interim /*&& (!style.isRemote || parent.active || parent.style.hidden)*/) { Window previous = parent.activeClient; parent.activeChild = this; if(!style.nonClient /*&& style.isActiveClient*/) { if(!style.hidden) { if(style.isActiveClient) parent.activeClient = this; // Moved UpdateActiveDocument inside hidden check // To prevent activating previous window while creating a new one // (It was messing up the privateModule in the CodeEditor) parent.UpdateActiveDocument(previous); } } } } //if(!style.isRemote) { if(rootWindow != this) { if(activateParent && parent && !parent.active /*parent != parent.parent.activeChild*/) parent.ActivateEx(true, true, moveInactive, activateRoot, external, externalSwap); } else #if !defined(__EMSCRIPTEN__) if(!guiApp.fullScreenMode) #endif { Window modalRoot = FindModal(); if(!modalRoot) modalRoot = this; if(!modalRoot.isForegroundWindow) { modalRoot.isForegroundWindow = true; // To check : Why is parent null? if(activateRoot && modalRoot.parent && !modalRoot.parent.display && external != modalRoot) { guiApp.interfaceDriver.ActivateRootWindow(modalRoot); } modalRoot.isForegroundWindow = false; } } } if(result && real && (!style.inactive || moveInactive) && parent) { Window last = parent.children.last; if(!style.stayOnTop) for(; last && last.style.stayOnTop; last = last.prev); parent.children.Move(this, last); // Definitely don't want that: why not? Update(null); if(order) parent.childrenOrder.Move(order, parent.childrenOrder.last); } } } else { if(!parent || style.interim || (parent.activeChild == this && !style.inactive)) { bool goOn = true; if(!style.interim) { if(parent) { parent.activeChild = null; if(!style.nonClient /*&& style.isActiveClient*/) { Window previous = parent.activeClient; if(style.isActiveClient) parent.activeClient = null; parent.UpdateActiveDocument(previous); } } } if(this == guiApp.interimWindow) { guiApp.interimWindow = null; if(guiApp.caretOwner) guiApp.caretOwner.UpdateCaret(false, false); } if(!PropagateActive(false, externalSwap, &goOn, true) || !goOn) { delete this; return false; } } } if(!active || !swap) UpdateDecorations(); if(swap) swap.UpdateDecorations(); if(active && rootWindow != this) ConsequentialMouseMove(false); } delete this; } return true; } // --- Input Messages --- void ::UpdateMouseMove(int mouseX, int mouseY, bool consequential) { static bool reEntrancy = false; if(reEntrancy) return; reEntrancy = true; guiApp.cursorUpdate = true; if(guiApp.windowScrolling && !consequential) { guiApp.windowScrolling.SetScrollPosition( (guiApp.windowScrolling.sbh) ? (guiApp.windowScrollingBefore.x - mouseX + guiApp.windowScrollingStart.x) : 0, (guiApp.windowScrolling.sbv) ? (guiApp.windowScrollingBefore.y - mouseY + guiApp.windowScrollingStart.y) : 0); } if(guiApp.windowMoving) { if(mouseX != guiApp.movingLast.x || mouseY != guiApp.movingLast.y) { Window window = guiApp.windowMoving; int rx, ry; int w = window.size.w; int h = window.size.h; int aw, ah; MinMaxValue ew, eh; int x, y; rx = mouseX - guiApp.windowMovingStart.x; ry = mouseY - guiApp.windowMovingStart.y; // Size window.GetDecorationsSize(&ew, &eh); if(guiApp.windowIsResizing) { x = window.scrolledPos.x; y = window.scrolledPos.y; if(guiApp.resizeX) { aw = Max(guiApp.windowResizingBefore.w - rx,window.skinMinSize.w); rx = guiApp.windowResizingBefore.w - aw; rx = Min(guiApp.windowMovingBefore.x + rx, window.parent.clientSize.w-1) - guiApp.windowMovingBefore.x; w = guiApp.windowResizingBefore.w - rx; } if(guiApp.resizeY) { ah = Max(guiApp.windowResizingBefore.h - ry,window.skinMinSize.h); ry = guiApp.windowResizingBefore.h - ah; ry = Min(guiApp.windowMovingBefore.y + ry, window.parent.clientSize.h-1) - guiApp.windowMovingBefore.y; ry = Max(ry, -guiApp.windowMovingBefore.y); h = guiApp.windowResizingBefore.h - ry; } if(guiApp.resizeEndX) { w = guiApp.windowResizingBefore.w + rx; w = Max(w,1-x); } if(guiApp.resizeEndY) h = guiApp.windowResizingBefore.h + ry; w -= ew; h -= eh; w = Max(w, 1); h = Max(h, 1); w = Max(w, window.minSize.w); h = Max(h, window.minSize.h); w = Min(w, window.maxSize.w); h = Min(h, window.maxSize.h); if(!window.OnResizing(&w, &h)) { w = window.clientSize.w; h = window.clientSize.h; } w = Max(w, window.skinMinSize.w); h = Max(h, window.skinMinSize.h); w += ew; h += eh; if(guiApp.textMode) { SNAPDOWN(w, textCellW); SNAPDOWN(h, textCellH); } if(guiApp.resizeX) { aw = Max(w,window.skinMinSize.w); rx = guiApp.windowResizingBefore.w - aw; rx = Min(guiApp.windowMovingBefore.x + rx, window.parent.clientSize.w-1) - guiApp.windowMovingBefore.x; w = guiApp.windowResizingBefore.w - rx; } if(guiApp.resizeY) { ah = Max(h,window.skinMinSize.h); ry = guiApp.windowResizingBefore.h - ah; ry = Min(guiApp.windowMovingBefore.y + ry, window.parent.clientSize.h-1) - guiApp.windowMovingBefore.y; ry = Max(ry, -guiApp.windowMovingBefore.y); h = guiApp.windowResizingBefore.h - ry; } } // Position if(!guiApp.windowIsResizing || guiApp.resizeX) x = guiApp.windowMovingBefore.x + rx; if(!guiApp.windowIsResizing || guiApp.resizeY) y = guiApp.windowMovingBefore.y + ry; if(!guiApp.windowIsResizing) { // Limit if(window.parent == guiApp.desktop && guiApp.virtualScreen.w) { x = Min(x, (guiApp.virtualScreen.w + guiApp.virtualScreenPos.x) -1); y = Min(y, (guiApp.virtualScreen.h + guiApp.virtualScreenPos.y) -1); x = Max(x,-(w-1) + guiApp.virtualScreenPos.x); y = Max(y,-(h-1) + guiApp.virtualScreenPos.y); } else { x = Min(x, (window.parent.reqScrollArea.w ? window.parent.reqScrollArea.w : window.parent.clientSize.w) -1); y = Min(y, (window.parent.reqScrollArea.h ? window.parent.reqScrollArea.h : window.parent.clientSize.h) -1); x = Max(x,-(w-1)); y = Max(y,-(h-1)); } } if(!guiApp.windowIsResizing || (guiApp.resizeX || guiApp.resizeY)) { if(!window.OnMoving(&x, &y, w, h)) { x = window.scrolledPos.x; y = window.scrolledPos.y; } } if(guiApp.textMode) { SNAPDOWN(x, textCellW); SNAPDOWN(y, textCellH); } if(!window.style.nonClient) { if(!window.style.fixed /*|| window.style.isDocument*/) { if(!window.style.dontScrollHorz) x += window.parent.scroll.x; if(!window.style.dontScrollVert) y += window.parent.scroll.y; } } // Break the anchors for moveable/resizable windows // Will probably cause problem with IDE windows... Will probably need a way to specify if anchors should break if(window.style.fixed) { if(window.state == normal) { window.normalAnchor = Anchor { left = x, top = y }; window.normalSizeAnchor = SizeAnchor { { w, h } }; window.anchored = false; } } window.stateAnchor = Anchor { left = x, top = y }; window.stateSizeAnchor = SizeAnchor { { w, h } }; window.Position(x, y, w, h, false, true, guiApp.windowIsResizing, guiApp.windowIsResizing, false, true); // TOCHECK: Investigate why the following only redraws the scrollbars //window.Position(x, y, w, h, false, true, true, true, false, true); guiApp.movingLast.x = mouseX; guiApp.movingLast.y = mouseY; } } reEntrancy = false; } public bool MultiTouchMessage(TouchPointerEvent event, Array infos, Modifiers * mods, bool consequential, bool activate) { bool result = true; if((infos && infos.count) || (event == up || event == pointerUp)) { Window w = null; while(result && w != this) { // TODO: How to handle this? int x = (infos && infos.count) ? infos[0].point.x : 0; int y = (infos && infos.count) ? infos[0].point.y : 0; Window msgWindow = GetAtPosition(x,y, false, true, w); Window window; delete w; w = msgWindow; if(w) incref w; window = (w && !w.disabled) ? w : null; if(guiApp.windowCaptured && (guiApp.windowCaptured.rootWindow == this)) { if(!guiApp.windowCaptured.isEnabled) guiApp.windowCaptured.ReleaseCapture(); else window = guiApp.windowCaptured; } if(consequential) mods->isSideEffect = true; if(!result || (window && window.destroyed)) window = null; if(window) { if(window.OnMultiTouch && !window.disabled) { Array in = null; if(infos && infos.count) { in = { size = infos.size }; memcpy(in.array, infos.array, sizeof(TouchPointerInfo) * infos.size); for(i : in) { i.point.x -= (window.absPosition.x + window.clientStart.x); i.point.y -= (window.absPosition.y + window.clientStart.y); i.point.x = Max(Min(i.point.x, 32767),-32768); i.point.y = Max(Min(i.point.y, 32767),-32768); } } incref window; if(!window.OnMultiTouch(event, in, *mods)) result = false; delete in; delete window; } } if(!result || !w || !w.clickThrough) break; } delete w; } return result; } public bool MouseMessage(uint method, int x, int y, Modifiers * mods, bool consequential, bool activate) { bool result = true; bool wasMoving = guiApp.windowMoving ? true : false; bool wasScrolling = guiApp.windowScrolling ? true : false; bool firstPass = true; Window w = null; while(result && w != this) { Window msgWindow = GetAtPosition(x,y, false, true, w); Window trueWindow = GetAtPosition(x,y, false, false, w); bool windowDragged = false; Window window; delete w; w = msgWindow; if(w) incref w; window = (w && !w.disabled) ? w : null; if(trueWindow) incref trueWindow; if(consequential) mods->isSideEffect = true; UpdateMouseMove(x, y, consequential); if(guiApp.windowCaptured && (guiApp.windowCaptured.rootWindow == this)) { if(!guiApp.windowCaptured.isEnabled) guiApp.windowCaptured.ReleaseCapture(); else window = guiApp.windowCaptured; } if(trueWindow && activate && (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick)) { if(mods->alt && !mods->ctrl && !mods->shift) { Window moved = trueWindow; for(moved = trueWindow; moved; moved = moved.parent) if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized)) break; if(moved) { window = moved; windowDragged = true; // Cancel the ALT menu toggling... window.rootWindow.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, 0, 0); } } } if(window && activate && (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick)) { Window modalWindow = window.FindModal(); /*if(mods->alt && !mods->shift && !mods->ctrl) { Window moved = window; for(moved = window; moved; moved = moved.parent) if(method == OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized)) break; if(moved) { window = moved; windowDragged = true; // Cancel the ALT menu toggling... window.rootWindow.KeyMessage(OnKeyDown, 0, 0); } }*/ if(!windowDragged) { Window activateWindow = modalWindow ? modalWindow : window; if(activateWindow && !activateWindow.isRemote) { bool doActivation = true; //bool needToDoActivation = false; Window check = activateWindow; for(check = activateWindow; check && check != guiApp.desktop; check = check.parent) { if(!check.style.inactive) { //needToDoActivation = true; if(check.active) doActivation = false; break; } } /* if(!needToDoActivation) doActivation = false; */ if((doActivation && (activateWindow.parent != guiApp.desktop || guiApp.fullScreen)) || (guiApp.interimWindow && !window.IsDescendantOf(guiApp.interimWindow))) { // Let the OnLeftButtonDown do the activating instead if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick) { window = null; result = true; } else //if(activate) { incref activateWindow; if(!activateWindow.ActivateEx(true, true, false, true, null, null)) { delete activateWindow; delete trueWindow; return false; } if(activateWindow._refCount == 1) { delete activateWindow; delete trueWindow; return false; } delete activateWindow; // Trouble with clickThrough, siblings and activation (Fix for nicktick scrolling, siblings/activation endless loops, #844) activate = false; } mods->isActivate = true; } } } if(!modalWindow && window && !window.destroyed) { if(!guiApp.windowCaptured || windowDragged) { if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown) { bool moving = ((window.state != maximized && window.IsMouseMoving( x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h))) || (guiApp.windowMoving && !guiApp.windowIsResizing); if(!moving && window.IsMouseResizing( x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h, &guiApp.resizeX, &guiApp.resizeY, &guiApp.resizeEndX, &guiApp.resizeEndY)) { guiApp.windowIsResizing = true; guiApp.windowResizingBefore.w = window.size.w; guiApp.windowResizingBefore.h = window.size.h; } if(guiApp.windowIsResizing || windowDragged || moving) { window.Capture(); guiApp.windowMoving = window; guiApp.windowMovingStart.x = guiApp.movingLast.x = x; guiApp.windowMovingStart.y = guiApp.movingLast.y = y; guiApp.windowMovingBefore.x = window.position.x;//s; guiApp.windowMovingBefore.y = window.position.y;//s; if(guiApp.windowMoving == guiApp.windowMoving.rootWindow) guiApp.interfaceDriver.StartMoving(guiApp.windowMoving.rootWindow, 0,0,false); } } else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown) { if(window.style.fixed && (windowDragged || window.IsMouseMoving( x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h))) { window.ShowSysMenu(x, y); result = false; } } else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown) { if(window.sbv || window.sbh) { window.Capture(); guiApp.windowScrolling = window; guiApp.windowScrollingStart.x = x; guiApp.windowScrollingStart.y = y; guiApp.windowScrollingBefore.x = window.scroll.x; guiApp.windowScrollingBefore.y = window.scroll.y; } } else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick) { if(window.style.hasMaximize && window.IsMouseMoving( x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h)) { window.SetState( (window.state == maximized) ? normal : maximized, false, *mods); result = false; } } } } else window = null; if(guiApp.windowMoving) { if(guiApp.windowMoving.parent) { if(guiApp.windowMoving.style.nonClient) guiApp.windowMoving.parent.SetMouseRangeToWindow(); else guiApp.windowMoving.parent.SetMouseRangeToClient(); } else FreeMouseRange(); window.UpdateDecorations(); } } else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp) { // Log("\n*** LEFT BUTTON UP ***\n"); if(guiApp.windowMoving) guiApp.windowMoving.StopMoving(); } else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp) { if(guiApp.windowScrolling) { Window windowScrolling = guiApp.windowScrolling; guiApp.windowScrolling = null; windowScrolling.ReleaseCapture(); } } if(!result || (window && window.destroyed)) window = null; if(window && window.FindModal()) window = null; if(trueWindow && trueWindow.FindModal()) delete trueWindow; /*if(trueWindow) incref trueWindow; */ /* msgWindow = GetAtPosition(x,y, true, false); if(msgWindow) msgWindow.SelectMouseCursor(); */ if(firstPass && (guiApp.windowCaptured || trueWindow)) { Window prevWindow = guiApp.prevWindow; List overWindows = guiApp.overWindows; Iterator it { overWindows }; while(it.Next()) { Window ww = it.data; if(trueWindow != ww && !trueWindow.IsDescendantOf(ww)) { it.pointer = null; result = ww.OnMouseLeave(*mods); if(!result) break; overWindows.TakeOut(ww); } } if(result && guiApp.prevWindow && trueWindow != guiApp.prevWindow) { guiApp.prevWindow.mouseInside = false; guiApp.prevWindow = null; if(result) { if(trueWindow.IsDescendantOf(prevWindow)) { if(!overWindows.Find(prevWindow)) overWindows.Add(prevWindow); } // Eventually fix this not to include captured? else if(!prevWindow.OnMouseLeave(*mods)) result = false; } } if(result && trueWindow && !trueWindow.destroyed/* && trueWindow == window*/) { Box box = trueWindow.box; box.left += trueWindow.absPosition.x; box.right += trueWindow.absPosition.x; box.top += trueWindow.absPosition.y; box.bottom += trueWindow.absPosition.y; if(box.IsPointInside({x, y}) && trueWindow != /*guiApp.*/prevWindow /*!trueWindow.mouseInside*/) { int overX = x - (trueWindow.absPosition.x + trueWindow.clientStart.x); int overY = y - (trueWindow.absPosition.y + trueWindow.clientStart.y); overX = Max(Min(overX, 32767),-32768); overY = Max(Min(overY, 32767),-32768); trueWindow.mouseInside = true; if(!trueWindow.OnMouseOver(overX, overY, *mods)) result = false; } } if(trueWindow && trueWindow._refCount > 1 && !trueWindow.destroyed) { for(wi : guiApp.overWindows; wi == trueWindow) { OnMouseLeave(0); guiApp.overWindows.TakeOut(wi); break; } guiApp.prevWindow = trueWindow; } else guiApp.prevWindow = null; } SelectMouseCursor(); if(window && ((!guiApp.windowMoving && !wasMoving) || (wasMoving && guiApp.windowMoving && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp)) && !wasScrolling) { int clientX = x - (window.absPosition.x + window.clientStart.x); int clientY = y - (window.absPosition.y + window.clientStart.y); bool (* MouseMethod)(Window instance, int x, int y, Modifiers mods); clientX = Max(Min(clientX, 32767),-32768); clientY = Max(Min(clientY, 32767),-32768); MouseMethod = (void *)window._vTbl[method]; if(MouseMethod /*&& !consequential*/ && !window.disabled) { incref window; if(!MouseMethod(window, clientX, clientY, *mods)) result = false; #ifdef __ANDROID__ if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp) window.OnMouseLeave(*mods); #endif delete window; } } delete trueWindow; /* if(result && w && w.clickThrough && w.parent) w = w.parent; else break; */ if(!result || !w || !w.clickThrough) break; firstPass = false; } delete w; return result; } // --- Mouse cursor management --- bool KeyMessage(uint method, Key key, unichar character) { bool status = true; if(!parent) { if(guiApp.interimWindow) this = guiApp.interimWindow; } #ifdef _DEBUG if((SmartKey)key != alt && (SmartKey)key != Key::control && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown && parent && this != parent.menuBar) Print(""); #endif if(!style.inactive || rootWindow != this) { bool (*KeyMethod)(Window window, Key key, unichar ch) = (void *)_vTbl[method]; Window modalWindow = FindModal(); Window interimMaster = master ? master.rootWindow : null; incref this; if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown) status = OnSysKeyDown(key, character); if(status && (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)) status = OnSysKeyHit(key, character); else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp) status = OnSysKeyUp(key, character); if(!status) { delete this; return true; } // Process Key Message for Internal UI Keyboard actions if(status && !destroyed && menuBar && state != minimized) { // Disable the ALT if((SmartKey)key != alt) menuBar.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, 0, 0); if(menuBar.focus) { SmartKey sk = (SmartKey) key; if((character && !key.alt && !key.ctrl) || sk == left || sk == right || sk == up || sk == down || sk == home || sk == end || sk == escape || sk == alt) { status = menuBar.KeyMessage(method, key, character); status = false; } else { if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown) menuBar.OnKeyHit(escape, 0); } if(!menuBar.focus && guiApp.caretOwner) guiApp.caretOwner.UpdateCaret(true, false); } } if(!destroyed && status) { if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown) { switch(key) { case left: case up: case right: case down: if(guiApp.windowMoving == this) { int step = 1; //8; int w = guiApp.windowMoving.size.w; int h = guiApp.windowMoving.size.h; int x = guiApp.windowMoving.scrolledPos.x; int y = guiApp.windowMoving.scrolledPos.y; if(guiApp.textMode) { if(key == down || key == up) step = Max(step, textCellH); else step = Max(step, textCellW); } if(guiApp.windowIsResizing) { switch(key) { case left: w-=step; break; case right: w+=step; break; case up: h-=step; break; case down: h+=step; break; } } else { switch(key) { case left: x-=step; break; case right: x+=step; break; case up: y-=step; break; case down: y+=step; break; } } if(guiApp.resizeX) x += w - guiApp.windowMoving.size.w; if(guiApp.resizeY) y += h - guiApp.windowMoving.size.h; if(!guiApp.windowIsResizing || guiApp.resizeX) x = (x - guiApp.windowMovingBefore.x) + guiApp.windowMovingStart.x; else x = (w - guiApp.windowResizingBefore.w) + guiApp.windowMovingStart.x; if(!guiApp.windowIsResizing || guiApp.resizeY) y = (y - guiApp.windowMovingBefore.y) + guiApp.windowMovingStart.y; else y = (h - guiApp.windowResizingBefore.h) + guiApp.windowMovingStart.y; guiApp.interfaceDriver.SetMousePosition(x, y); ConsequentialMouseMove(true); status = false; } break; case escape: case enter: case keyPadEnter: if(guiApp.windowMoving && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown) { guiApp.windowMoving.StopMoving(); ConsequentialMouseMove(false); status = false; } break; case altSpace: if(style.fixed) { ShowSysMenu(absPosition.x, absPosition.y); status = false; } break; } } } if(!destroyed && status && state != minimized) { // Process all the way down the children if(activeChild && !activeChild.disabled) { status = activeChild.KeyMessage(method, key, character); } if(status && activeClient && activeChild != activeClient && !activeClient.disabled && (key.alt || key.ctrl) && key.code != left && key.code != right && key.code != up && key.code != down) { status = activeClient.KeyMessage(method, key, character); } // Default Control if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown) { if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && !defaultControl.disabled && state != minimized) // && defaultControl != activeChild) { delete previousActive; previousActive = activeChild; if(previousActive) incref previousActive; ConsequentialMouseMove(false); if((defaultControl.active || defaultControl.ActivateEx(true, true, false, true, null, null)) && !defaultControl.disabled) defaultControl.KeyMessage(method, defaultKey, character); status = false; } } } if(!destroyed && status && (!modalWindow || this == guiApp.desktop)) { if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown) { switch(key) { case altMinus: if(style.fixed) { ShowSysMenu(absPosition.x, absPosition.y); status = false; } break; //case f5: /* case shiftF5: if(this != guiApp.desktop) { if(!guiApp.windowMoving && !guiApp.windowCaptured) { if(state != maximized && (key.shift ? style.sizeable : style.fixed)) { MenuMoveOrSize(key.shift, true); status = false; } } else if(guiApp.windowMoving) { guiApp.windowMoving.StopMoving(); ConsequentialMouseMove(false); status = false; } } break; */ } } if(!destroyed && status && state != minimized) { if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown) { switch(key) { case tab: case shiftTab: { Window cycleParent = this; if(this == guiApp.interimWindow && master && !master.style.interim && !cycleParent.style.tabCycle && master.parent) cycleParent = master.parent; if(!guiApp.windowCaptured && cycleParent.style.tabCycle) { if(cycleParent.CycleChildren(!key.shift, false, false, true)) { /* Window child = cycleParent.activeChild; // Scroll the window to include the active control if(cycleParent.sbh && !child.style.dontScrollHorz) { if(child.scrolledPos.x < 0) cycleParent.sbh.Action(Position, cycleParent.scroll.x + child.scrolledPos.x, 0); else if(child.scrolledPos.x + child.size.w > cycleParent.clientSize.w) cycleParent.sbh.Action(Position, cycleParent.scroll.x + child.scrolledPos.x + child.size.w - cycleParent.clientSize.w, 0); } if(cycleParent.sbv && !child.style.dontScrollVert) { if(child.scrolledPos.y < 0) cycleParent.sbv.Action(Position, cycleParent.scroll.y + child.scrolledPos.y, 0); else if(child.scrolledPos.y + child.size.w > window.clientSize.h) cycleParent.sbv.Action(Position, cycleParent.scroll.y + child.scrolledPos.y+child.size.h - cycleParent.clientSize.h, 0); } */ cycleParent.ConsequentialMouseMove(false); status = false; } } break; } case f6: case shiftF6: if(!guiApp.windowMoving /*!guiApp.windowCaptured*/) { // NOT NEEDED... guiApp.windowMoving.ReleaseCapture(); if(parent == guiApp.desktop) if(guiApp.desktop.CycleChildren(key.shift, true, false, true)) { status = false; break; } if(style.tabCycle) { delete this; return true; } if(CycleChildren(key.shift, true, false, true)) { status = false; break; } } break; /* // mIRC Style Window Shortcuts case alt1: case alt2: case alt3: case alt4: case alt5: case alt6: case alt7: case alt8: case alt9: case alt0: { if(numPositions) { Window document; for(document = children.first; document; document = document.next) { if(document.style.isDocument && document.documentID - 1 == key.code - k1) { if(document == activeChild) { if(document.state == minimized) document.SetState(normal, false, key); else { document.SetState(minimized, false, key); CycleChildren(false, true, false); } } else { if(activeChild.state == maximized && document.style.hasMaximize) document.SetState(maximized, false, key); else if(document.state == minimized) document.SetState(normal, false, key); document.Activate(); } status = false; break; } } } break; } */ } } } } if(!destroyed && status) { if(state == minimized) { delete this; return true; } if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp) { if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && previousActive) { if(defaultControl.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, key, character)) previousActive.ActivateEx(true, false, false, true, null, null); delete previousActive; status = false; } } } if(!destroyed && status) { status = ProcessHotKeys(method, key, character); } if(!destroyed && status && !modalWindow && state != minimized) { if(KeyMethod) status = KeyMethod(this, key, character); if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown) status = OnKeyHit(key, character); if(!destroyed && status && (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)) { bool result = false; switch(key) { case ctrlUp: case ctrlDown: if(sbv && !guiApp.windowScrolling) result = sbv.Action((key == ctrlUp) ? up : down, 0, key); break; case wheelUp: case wheelDown: if(sbv && !guiApp.windowScrolling) { result = sbv.Action((key == wheelUp) ? wheelUp : wheelDown, 0, key); // Do we want to do a consequential move regardless of result in this case? ConsequentialMouseMove(false); } break; case ctrlPageUp: case ctrlPageDown: if(sbh && !guiApp.windowScrolling) result = sbh.Action((key == ctrlPageUp) ? up : down, 0, key); break; } if(result) { ConsequentialMouseMove(false); status = false; } } } if(status && !destroyed && menuBar && state != minimized) status = menuBar.KeyMessage(method, key, character); if(style.interim && /*destroyed && */status && interimMaster) { // Testing this... for Ctrl-O to open dialog when autocompletion listbox is popped... status = interimMaster.KeyMessage(method, key, character); } delete this; } return status; } bool ProcessHotKeys(uint method, Key key, unichar character) { bool status = true; HotKeySlot hotKey; for(hotKey = hotKeys.first; hotKey; hotKey = hotKey.next) if((hotKey.key == key || (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp && hotKey.key.code == key.code)) && !hotKey.window.disabled && (hotKey.window.style.nonClient || state != minimized)) { Window hotKeyWindow = hotKey.window; Window parent = hotKeyWindow.parent; Window prevActiveWindow = activeChild; // For when sys buttons are placed inside the menu bar if(parent && parent._class == class(PopupMenu)) parent = parent.parent; // Don't process non-visible buttons, but make an exception for the Alt-F4 with Native Decorations turned on; This handles alt+enter as well if(hotKeyWindow.style.hidden && (!hotKeyWindow.style.nonClient || !parent || !parent.nativeDecorations || (hotKeyWindow != parent.sysButtons[2] && hotKeyWindow != parent.sysButtons[1]))) continue; if(prevActiveWindow) incref prevActiveWindow; incref hotKeyWindow; if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown && !hotKeyWindow.style.nonClient && !hotKeyWindow.inactive) if(!hotKeyWindow.ActivateEx(true, true, false, true, null, null)) { status = false; delete hotKeyWindow; delete prevActiveWindow; break; } if(hotKeyWindow.style.nonClient && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit) method = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown; if(!hotKeyWindow.KeyMessage(method, Key::hotKey, character)) { // ********* WORKING ON THIS *********** if(prevActiveWindow && !guiApp.interimWindow) prevActiveWindow.ActivateEx(true, false, false, false, null, null); status = false; } else if(hotKeyWindow.style.inactive) status = hotKeyWindow.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, Key::hotKey, character); delete prevActiveWindow; delete hotKeyWindow; // For Key Ups, don't set status to false... (e.g.: Releasing Enter vs AltEnter hot key) if(method != __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp) status = false; break; } if(status && tabCycle) { Window child; for(child = children.first; child; child = child.next) { if(child.tabCycle && !child.ProcessHotKeys(method, key, character)) { status = false; break; } } } return status; } // --- Windows and graphics initialization / termination --- bool SetupRoot(void) { Window child; // Setup relationship with outside world (bb root || !bb) #if defined(__EMSCRIPTEN__) if(this == guiApp.desktop) #else if((!guiApp.fullScreenMode && parent == guiApp.desktop) || this == guiApp.desktop || (_displayDriver && parent.dispDriver && dispDriver != parent.dispDriver)) #endif { rootWindow = this; if(!tempExtents) tempExtents = new0 Extent[4]; against = null; } else { /*if(guiApp.fullScreenMode) rootWindow = guiApp.desktop; else*/ //rootWindow = parent.created ? parent.rootWindow : null; rootWindow = parent.rootWindow; if(style.nonClient) against = &parent.box; else against = &parent.clientArea; } for(child = children.first; child; child = child.next) child.SetupRoot(); return (rootWindow && (rootWindow == this || rootWindow.created)) ? true : false; } bool Setup(bool positionChildren) { bool result = false; Window child; #if defined(__EMSCRIPTEN__) if(this == guiApp.desktop) #else if((!guiApp.fullScreenMode && parent == guiApp.desktop) || (guiApp.fullScreenMode && (this == guiApp.desktop || (_displayDriver && parent.dispDriver && dispDriver != parent.dispDriver)))) #endif { subclass(DisplayDriver) dDriver = (dispDriver && !formDesigner) ? dispDriver : GetDisplayDriver(guiApp.defaultDisplayDriver); DisplaySystem displaySystem = dDriver ? dDriver.displaySystem : null; if(!windowHandle) windowHandle = dDriver.printer ? null : guiApp.interfaceDriver.CreateRootWindow(this); // This was here, is it really needed? //guiApp.interfaceDriver.ActivateRootWindow(this); if(!displaySystem) { displaySystem = DisplaySystem { glCapabilities = glCapabilities }; if(!displaySystem.Create(dDriver.name, guiApp.fullScreenMode ? windowHandle : windowHandle /*null*/, guiApp.fullScreenMode)) { delete displaySystem; } } if(displaySystem) { display = Display { alphaBlend = alphaBlend, useSharedMemory = useSharedMemory, glCapabilities = glCapabilities, windowDriverData = windowData }; if(display.Create(displaySystem, windowHandle)) result = true; else { delete display; } } // Sometimes icon does not show up on Windows XP if we set here... // guiApp.interfaceDriver.SetIcon(this, icon); } else if(this != guiApp.desktop) { display = rootWindow ? rootWindow.display : null; result = true; } else result = true; if(guiApp.acquiredWindow && rootWindow == guiApp.acquiredWindow.rootWindow) guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, true); for(child = children.first; child; child = child.next) { if(child.created && !child.Setup(false)) result = false; if(guiApp.modeSwitching && guiApp.fullScreen && child.rootWindow == child) child.UpdateCaption(); } return result; } bool SetupDisplay(void) { #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA) if(is3D) return Window3D_SetupDisplay(this); else #endif if(SetupRoot()) return Setup(true); return false; } class_data void ** pureVTbl; bool LoadGraphics(bool creation, bool resetAnchors) { bool result = false; bool success = false; Window child; WindowState stateBackup = state; if(((subclass(Window))_class).pureVTbl) { if(_vTbl == _class._vTbl) { _vTbl = ((subclass(Window))_class).pureVTbl; } else { int m; for(m = 0; m < _class.vTblSize; m++) { if(_vTbl[m] == _class._vTbl[m]) _vTbl[m] = ((subclass(Window))_class).pureVTbl[m]; } } } if(guiApp.currentSkin && ((subclass(Window))_class).pureVTbl) { if(_vTbl == ((subclass(Window))_class).pureVTbl) { _vTbl = _class._vTbl; } else { int m; for(m = 0; m < _class.vTblSize; m++) { if(_vTbl[m] == ((subclass(Window))_class).pureVTbl[m]) _vTbl[m] = _class._vTbl[m]; } } } if( #if !defined(__EMSCRIPTEN__) guiApp.fullScreenMode || #endif this != guiApp.desktop) { SetWindowMinimum(&skinMinSize.w, &skinMinSize.h); if(display) { ResPtr ptr; success = true; display.Lock(false); if(rootWindow == this) { // Set Color Palette display.SetPalette(palette, true); // Load Cursors /* if(guiApp.fullScreenMode && this == guiApp.desktop) { int c; Cursor cursor; for(c=0; c size - 2) { idBuffer = renew0 idBuffer byte[size*2]; memset(idBuffer + size, 0, size); size *= 2; } idBuffer[child.iconID] = (byte)bool::true; } } for(c = 0; c 0) ? tx & 0xFFFFF : tx; //position.y = (ty > 0) ? ty & 0xFFFFF : ty; ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h); if(state != minimized || hasMinimize) Position(x, y, w, h, true, true, true, true, false, true); if(!style.inactive && !style.interim && parent && this == parent.activeClient) parent.UpdateActiveDocument(null); } if(state != minimized || hasMinimize) CreateSystemChildren(); // ------------------------------------------------------ } int GetPositionID(Window forChild) { Window child; int size = 256; byte * idBuffer = new0 byte[size]; int c; for(child = children.first; child; child = child.next) { if(child.style.isActiveClient && !child.style.hidden && child != forChild) { if(child.positionID > size - 2) { idBuffer = renew0 idBuffer byte[size*2]; memset(idBuffer + size, 0, size); size *= 2; } idBuffer[child.positionID] = (byte)bool::true; } } for(c = 0; c size - 2) { idBuffer = renew0 idBuffer byte[size*2]; memset(idBuffer + size, 0, size); size *= 2; } idBuffer[child.documentID-1] = 1; } } for(c = 0; c