diff --git a/src/confscreen.cpp b/src/confscreen.cpp index 8fca9c0..a41f85e 100644 --- a/src/confscreen.cpp +++ b/src/confscreen.cpp @@ -161,6 +161,11 @@ void TextWindow::ScreenChangeAutosaveInterval(int link, uint32_t v) { SS.TW.edit.meaning = Edit::AUTOSAVE_INTERVAL; } +void TextWindow::ScreenChangeTextPaneEnabled(int link, uint32_t v) { + SS.GW.dockTextWindow = !SS.GW.dockTextWindow; + ShowTextWindow(SS.GW.showTextWindow && !SS.GW.dockTextWindow); +} + void TextWindow::ShowConfiguration() { int i; Printf(true, "%Ft user color (r, g, b)"); @@ -303,6 +308,11 @@ void TextWindow::ShowConfiguration() { Printf(false, "%Ba %d %Fl%Ll%f[change]%E", SS.autosaveInterval, &ScreenChangeAutosaveInterval); + Printf(false, ""); + Printf(false, " %Fd%f%Ll%s single window UI%E", + &ScreenChangeTextPaneEnabled, + SS.GW.dockTextWindow ? CHECK_TRUE : CHECK_FALSE); + if(canvas) { const char *gl_vendor, *gl_renderer, *gl_version; canvas->GetIdent(&gl_vendor, &gl_renderer, &gl_version); diff --git a/src/draw.cpp b/src/draw.cpp index 548df02..81c9f16 100644 --- a/src/draw.cpp +++ b/src/draw.cpp @@ -751,14 +751,7 @@ void GraphicsWindow::Paint() { havePainted = true; - int w, h; - GetGraphicsWindowSize(&w, &h); - width = w; - height = h; - - Camera camera = GetCamera(); Lighting lighting = GetLighting(); - if(!SS.ActiveGroupsOkay()) { // Draw a different background whenever we're having solve problems. RgbaColor bgColor = Style::Color(Style::DRAW_ERROR); @@ -770,9 +763,22 @@ void GraphicsWindow::Paint() { ForceTextWindowShown(); } + int windowWidth, windowHeight; + GetGraphicsWindowSize(&windowWidth, &windowHeight); + if(showTextWindow && dockTextWindow) { + width = windowWidth - textDockWidth; + height = windowHeight; + + SS.TW.Paint(canvas, windowWidth - textDockWidth, 0, textDockWidth, windowHeight); + } else { + width = windowWidth; + height = windowHeight; + } + Camera camera = GetCamera(); + auto renderStartTime = std::chrono::high_resolution_clock::now(); - canvas->NewFrame(); + canvas->NewFrame(0, 0, width, height); canvas->SetCamera(camera); canvas->SetLighting(lighting); Draw(canvas.get()); diff --git a/src/graphicswin.cpp b/src/graphicswin.cpp index 2dc1a2f..a956a40 100644 --- a/src/graphicswin.cpp +++ b/src/graphicswin.cpp @@ -235,7 +235,7 @@ void GraphicsWindow::Init() { drawOccludedAs = DrawOccludedAs::INVISIBLE; showTextWindow = true; - ShowTextWindow(showTextWindow); + ShowTextWindow(showTextWindow && !dockTextWindow); showSnapGrid = false; context.active = false; @@ -687,7 +687,7 @@ void GraphicsWindow::EnsureValidActives() { RadioMenuByCmd(Command::UNITS_MM, SS.viewUnits == Unit::MM); RadioMenuByCmd(Command::UNITS_INCHES, SS.viewUnits == Unit::INCHES); - ShowTextWindow(SS.GW.showTextWindow); + ShowTextWindow(showTextWindow && !dockTextWindow); CheckMenuByCmd(Command::SHOW_TEXT_WND, /*checked=*/SS.GW.showTextWindow); #if defined(__APPLE__) @@ -722,7 +722,7 @@ void GraphicsWindow::ForceTextWindowShown() { if(!showTextWindow) { showTextWindow = true; CheckMenuByCmd(Command::SHOW_TEXT_WND, /*checked=*/true); - ShowTextWindow(true); + ShowTextWindow(!dockTextWindow); } } diff --git a/src/mouse.cpp b/src/mouse.cpp index 7b0ff4b..35a431d 100644 --- a/src/mouse.cpp +++ b/src/mouse.cpp @@ -75,9 +75,27 @@ void GraphicsWindow::StartDraggingBySelection() { if(hover.entity.v) StartDraggingByEntity(hover.entity); } +bool GraphicsWindow::ConvertMouseCoords(double *x, double *y) { + if(showTextWindow && dockTextWindow) { + if(*x > width) { + *x -= width; + return true; + } + } + + // Convert to OpenGL coordinates. + *x = *x - width / 2; + *y = height / 2 - *y; + return false; +} + void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, - bool middleDown, bool rightDown, bool shiftDown, bool ctrlDown) -{ + bool middleDown, bool rightDown, bool shiftDown, bool ctrlDown) { + if(ConvertMouseCoords(&x, &y)) { + SS.TW.MouseEvent(/*isClick=*/(leftDown || middleDown || rightDown), leftDown, x, y); + return; + } + if(GraphicsEditControlIsVisible()) return; if(context.active) return; @@ -470,6 +488,11 @@ void GraphicsWindow::ClearPending() { } void GraphicsWindow::MouseMiddleOrRightDown(double x, double y) { + if(ConvertMouseCoords(&x, &y)) { + SS.TW.MouseEvent(/*isClick=*/true, /*leftDown=*/false, x, y); + return; + } + if(GraphicsEditControlIsVisible()) return; orig.offset = offset; @@ -498,6 +521,8 @@ void GraphicsWindow::ContextMenuListStyles() { } void GraphicsWindow::MouseRightUp(double x, double y) { + if(ConvertMouseCoords(&x, &y)) return; + SS.extraLine.draw = false; InvalidateGraphics(); @@ -893,7 +918,14 @@ bool GraphicsWindow::ConstrainPointByHovered(hEntity pt) { return false; } -void GraphicsWindow::MouseLeftDown(double mx, double my) { +void GraphicsWindow::MouseLeftDown(double origMx, double origMy) { + double mx = origMx, + my = origMy; + if(ConvertMouseCoords(&mx, &my)) { + SS.TW.MouseEvent(/*isClick=*/true, /*leftDown=*/true, mx, my); + return; + } + orig.mouseDown = true; if(GraphicsEditControlIsVisible()) { @@ -912,7 +944,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) { bool hasConstraintSuggestion = SS.GW.pending.hasSuggestion; // Make sure the hover is up to date. - MouseMoved(mx, my, /*leftDown=*/false, /*middleDown=*/false, /*rightDown=*/false, + MouseMoved(origMx, origMy, /*leftDown=*/false, /*middleDown=*/false, /*rightDown=*/false, /*shiftDown=*/false, /*ctrlDown=*/false); orig.mouse.x = mx; orig.mouse.y = my; @@ -1232,6 +1264,8 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) { } void GraphicsWindow::MouseLeftUp(double mx, double my) { + if(ConvertMouseCoords(&mx, &my)) return; + orig.mouseDown = false; hoverWasSelectedOnMousedown = false; @@ -1272,6 +1306,8 @@ void GraphicsWindow::MouseLeftUp(double mx, double my) { } void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) { + if(ConvertMouseCoords(&mx, &my)) return; + if(GraphicsEditControlIsVisible()) return; SS.TW.HideEditControl(); @@ -1335,13 +1371,19 @@ void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) { } hStyle hs = c->disp.style; if(hs.v == 0) hs.v = Style::CONSTRAINT; - ShowGraphicsEditControl((int)p2.x, (int)p2.y, + SS.TW.editControl.inDock = false; + ShowGraphicsEditControl((int)p2.x + width / 2, height / 2 - (int)p2.y, (int)(VectorFont::Builtin()->GetHeight(Style::TextHeight(hs))), - editMinWidthChar, editValue); + editMinWidthChar, editValue, /*forDock=*/false); } } void GraphicsWindow::EditControlDone(const char *s) { + if(SS.TW.editControl.inDock) { + SS.TW.EditControlDone(s); + return; + } + HideGraphicsEditControl(); Constraint *c = SK.GetConstraint(constraintBeingEdited); @@ -1416,6 +1458,11 @@ bool GraphicsWindow::KeyDown(int c) { } void GraphicsWindow::MouseScroll(double x, double y, int delta) { + if(ConvertMouseCoords(&x, &y)) { + // FIXME SS.TW.MouseScroll(x, y, delta); + return; + } + double offsetRight = offset.Dot(projRight); double offsetUp = offset.Dot(projUp); diff --git a/src/platform/cocoamain.mm b/src/platform/cocoamain.mm index 9b87514..2de41d7 100644 --- a/src/platform/cocoamain.mm +++ b/src/platform/cocoamain.mm @@ -287,7 +287,7 @@ CONVERT(Rect) } - (void)mouseMoved:(NSEvent*)event { - NSPoint point = [self ij_to_xy:[self convertPoint:[event locationInWindow] fromView:nil]]; + NSPoint point = [self xyFromEvent:event]; NSUInteger flags = [event modifierFlags]; NSUInteger buttons = [NSEvent pressedMouseButtons]; SolveSpace::SS.GW.MouseMoved(point.x, point.y, @@ -311,7 +311,7 @@ CONVERT(Rect) } - (void)mouseDown:(NSEvent*)event { - NSPoint point = [self ij_to_xy:[self convertPoint:[event locationInWindow] fromView:nil]]; + NSPoint point = [self xyFromEvent:event]; if([event clickCount] == 1) SolveSpace::SS.GW.MouseLeftDown(point.x, point.y); else if([event clickCount] == 2) @@ -319,7 +319,7 @@ CONVERT(Rect) } - (void)rightMouseDown:(NSEvent*)event { - NSPoint point = [self ij_to_xy:[self convertPoint:[event locationInWindow] fromView:nil]]; + NSPoint point = [self xyFromEvent:event]; SolveSpace::SS.GW.MouseMiddleOrRightDown(point.x, point.y); } @@ -328,18 +328,18 @@ CONVERT(Rect) } - (void)mouseUp:(NSEvent*)event { - NSPoint point = [self ij_to_xy:[self convertPoint:[event locationInWindow] fromView:nil]]; + NSPoint point = [self xyFromEvent:event]; SolveSpace::SS.GW.MouseLeftUp(point.x, point.y); } - (void)rightMouseUp:(NSEvent*)event { - NSPoint point = [self ij_to_xy:[self convertPoint:[event locationInWindow] fromView:nil]]; + NSPoint point = [self xyFromEvent:event]; self->_lastContextMenuEvent = event; SolveSpace::SS.GW.MouseRightUp(point.x, point.y); } - (void)scrollWheel:(NSEvent*)event { - NSPoint point = [self ij_to_xy:[self convertPoint:[event locationInWindow] fromView:nil]]; + NSPoint point = [self xyFromEvent:event]; SolveSpace::SS.GW.MouseScroll(point.x, point.y, (int)-[event deltaY]); } @@ -369,16 +369,11 @@ CONVERT(Rect) } - (void)startEditing:(NSString*)text at:(NSPoint)xy withHeight:(double)fontHeight - withMinWidthInChars:(int)minWidthChars { - // Convert to ij (vs. xy) style coordinates + withMinWidthInChars:(int)minWidthChars usingMonospace:(BOOL)isMonospace { NSSize size = [self convertSizeToBacking:[self bounds].size]; - NSPoint point = { - .x = xy.x + size.width / 2, - .y = xy.y - size.height / 2 - }; + NSPoint point = [self convertPointFromBacking:NSMakePoint(xy.x, size.height - xy.y)]; [[self window] makeKeyWindow]; - [super startEditing:text at:[self convertPointFromBacking:point] - withHeight:fontHeight usingMonospace:FALSE]; + [super startEditing:text at:point withHeight:fontHeight usingMonospace:isMonospace]; [self prepareEditorWithMinWidthInChars:minWidthChars]; } @@ -404,12 +399,11 @@ CONVERT(Rect) [self stopEditing]; } -- (NSPoint)ij_to_xy:(NSPoint)ij { - // Convert to xy (vs. ij) style coordinates, - // with (0, 0) at center +- (NSPoint)xyFromEvent:event { + NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil] NSSize size = [self bounds].size; return [self convertPointToBacking:(NSPoint){ - .x = ij.x - size.width / 2, .y = ij.y - size.height / 2 }]; + .x = point.x, .y = size.height - point.y }]; } @end @@ -492,11 +486,12 @@ bool FullScreenIsActive(void) { } void ShowGraphicsEditControl(int x, int y, int fontHeight, int minWidthChars, - const std::string &str) { + const std::string &str, bool forDock) { [GWView startEditing:[NSString stringWithUTF8String:str.c_str()] at:(NSPoint){(CGFloat)x, (CGFloat)y} - withHeight:fontHeight - withMinWidthInChars:minWidthChars]; + withHeight:(forDock ? 15 : fontHeight) + withMinWidthInChars:minWidthChars + usingMonospace:(forDock ? TRUE : FALSE)]; } void HideGraphicsEditControl(void) { @@ -1062,7 +1057,7 @@ double GetScreenDpi() { return (displayPixelSize.width / displayPhysicalSize.width) * 25.4f; } -void InvalidateText(void) { +void InvalidateText() { NSSize size = [TWView convertSizeToBacking:[TWView frame].size]; size.height = (SS.TW.top[SS.TW.rows - 1] + 1) * TextWindow::LINE_HEIGHT / 2; [TWView setFrameSize:[TWView convertSizeFromBacking:size]]; diff --git a/src/platform/gtkmain.cpp b/src/platform/gtkmain.cpp index 60e210a..5021814 100644 --- a/src/platform/gtkmain.cpp +++ b/src/platform/gtkmain.cpp @@ -298,6 +298,17 @@ public: glXDestroyContext(_xdisplay, _glcontext); } + void set_cursor_hand(bool is_hand) { + realize(); + + Gdk::CursorType type = is_hand ? Gdk::HAND1 : Gdk::ARROW; +#ifdef HAVE_GTK3 + get_window()->set_cursor(Gdk::Cursor::create(type)); +#else + get_window()->set_cursor(Gdk::Cursor(type)); +#endif + } + protected: /* Draw on a GLX framebuffer object, then read pixels out and draw them on the Cairo context. Slower, but you get to overlay nice widgets. */ @@ -353,6 +364,11 @@ public: _entry.signal_activate(). connect(sigc::mem_fun(this, &EditorOverlay::on_activate)); + + _entry.signal_motion_notify_event(). + connect(sigc::mem_fun(this, &EditorOverlay::on_editor_motion_notify_event)); + _entry.signal_button_press_event(). + connect(sigc::mem_fun(this, &EditorOverlay::on_editor_button_press_event)); } void start_editing(int x, int y, int font_height, bool is_monospace, int minWidthChars, @@ -451,6 +467,14 @@ protected: _signal_editing_done(_entry.get_text()); } + bool on_editor_motion_notify_event(GdkEventMotion *event) { + return _underlay.event((GdkEvent*) event); + } + + bool on_editor_button_press_event(GdkEventButton *event) { + return _underlay.event((GdkEvent*) event); + } + private: Gtk::Widget &_underlay; Gtk::Entry _entry; @@ -495,22 +519,12 @@ public: } protected: - bool on_configure_event(GdkEventConfigure *event) override { - _w = event->width; - _h = event->height; - - return GlWidget::on_configure_event(event);; - } - void on_gl_draw() override { SS.GW.Paint(); } bool on_motion_notify_event(GdkEventMotion *event) override { - int x, y; - ij_to_xy(event->x, event->y, x, y); - - SS.GW.MouseMoved(x, y, + SS.GW.MouseMoved(event->x, event->y, event->state & GDK_BUTTON1_MASK, event->state & GDK_BUTTON2_MASK, event->state & GDK_BUTTON3_MASK, @@ -521,20 +535,17 @@ protected: } bool on_button_press_event(GdkEventButton *event) override { - int x, y; - ij_to_xy(event->x, event->y, x, y); - switch(event->button) { case 1: if(event->type == GDK_BUTTON_PRESS) - SS.GW.MouseLeftDown(x, y); + SS.GW.MouseLeftDown(event->x, event->y); else if(event->type == GDK_2BUTTON_PRESS) - SS.GW.MouseLeftDoubleClick(x, y); + SS.GW.MouseLeftDoubleClick(event->x, event->y); break; case 2: case 3: - SS.GW.MouseMiddleOrRightDown(x, y); + SS.GW.MouseMiddleOrRightDown(event->x, event->y); break; } @@ -542,16 +553,13 @@ protected: } bool on_button_release_event(GdkEventButton *event) override { - int x, y; - ij_to_xy(event->x, event->y, x, y); - switch(event->button) { case 1: - SS.GW.MouseLeftUp(x, y); + SS.GW.MouseLeftUp(event->x, event->y); break; case 3: - SS.GW.MouseRightUp(x, y); + SS.GW.MouseRightUp(event->x, event->y); break; } @@ -559,10 +567,7 @@ protected: } bool on_scroll_event(GdkEventScroll *event) override { - int x, y; - ij_to_xy(event->x, event->y, x, y); - - SS.GW.MouseScroll(x, y, (int)-DeltaYOfScrollEvent(event)); + SS.GW.MouseScroll(event->x, event->y, (int)-DeltaYOfScrollEvent(event)); return true; } @@ -572,15 +577,6 @@ protected: return true; } - -private: - int _w, _h; - void ij_to_xy(double i, double j, int &x, int &y) { - // Convert to xy (vs. ij) style coordinates, - // with (0, 0) at center - x = (int)i - _w / 2; - y = _h / 2 - (int)j; - } }; class GraphicsWindowGtk : public Gtk::Window { @@ -748,16 +744,9 @@ bool FullScreenIsActive(void) { } void ShowGraphicsEditControl(int x, int y, int fontHeight, int minWidthChars, - const std::string &val) { - Gdk::Rectangle rect = GW->get_widget().get_allocation(); - - // Convert to ij (vs. xy) style coordinates, - // and compensate for the input widget height due to inverse coord - int i, j; - i = x + rect.get_width() / 2; - j = -y + rect.get_height() / 2; - - GW->get_overlay().start_editing(i, j, fontHeight, /*is_monospace=*/false, minWidthChars, val); + const std::string &val, bool forDock) { + GW->get_overlay().start_editing(x, y, fontHeight, + /*is_monospace=*/forDock, minWidthChars, val); } void HideGraphicsEditControl(void) { @@ -1260,34 +1249,22 @@ public: Gdk::LEAVE_NOTIFY_MASK); } - void set_cursor_hand(bool is_hand) { - Glib::RefPtr gdkwin = get_window(); - if(gdkwin) { // returns NULL if not realized - Gdk::CursorType type = is_hand ? Gdk::HAND1 : Gdk::ARROW; -#ifdef HAVE_GTK3 - gdkwin->set_cursor(Gdk::Cursor::create(type)); -#else - gdkwin->set_cursor(Gdk::Cursor(type)); -#endif - } - } - protected: void on_gl_draw() override { SS.TW.Paint(); } bool on_motion_notify_event(GdkEventMotion *event) override { - SS.TW.MouseEvent(/*leftClick*/ false, - /*leftDown*/ event->state & GDK_BUTTON1_MASK, + SS.TW.MouseEvent(/*isClick=*/false, + /*leftDown=*/event->state & GDK_BUTTON1_MASK, event->x, event->y); return true; } bool on_button_press_event(GdkEventButton *event) override { - SS.TW.MouseEvent(/*leftClick*/ event->type == GDK_BUTTON_PRESS, - /*leftDown*/ event->state & GDK_BUTTON1_MASK, + SS.TW.MouseEvent(/*isClick=*/event->type == GDK_BUTTON_PRESS, + /*leftDown=*/event->state & GDK_BUTTON1_MASK, event->x, event->y); return true; @@ -1333,11 +1310,6 @@ public: _overlay.signal_editing_done(). connect(sigc::mem_fun(this, &TextWindowGtk::on_editing_done)); - - _overlay.get_entry().signal_motion_notify_event(). - connect(sigc::mem_fun(this, &TextWindowGtk::on_editor_motion_notify_event)); - _overlay.get_entry().signal_button_press_event(). - connect(sigc::mem_fun(this, &TextWindowGtk::on_editor_button_press_event)); } Gtk::VScrollbar &get_scrollbar() { @@ -1388,14 +1360,6 @@ protected: SS.TW.EditControlDone(value.c_str()); } - bool on_editor_motion_notify_event(GdkEventMotion *event) { - return _widget.event((GdkEvent*) event); - } - - bool on_editor_button_press_event(GdkEventButton *event) { - return _widget.event((GdkEvent*) event); - } - private: Gtk::VScrollbar _scrollbar; TextWidget _widget; @@ -1423,6 +1387,11 @@ double GetScreenDpi() { } void InvalidateText(void) { + if(SS.GW.dockTextWindow) { + InvalidateGraphics(); + return; + } + TW->get_widget().queue_draw(); } @@ -1431,7 +1400,11 @@ void MoveTextScrollbarTo(int pos, int maxPos, int page) { } void SetMousePointerToHand(bool is_hand) { - TW->get_widget().set_cursor_hand(is_hand); + if(SS.GW.dockTextWindow) { + GW->get_widget().set_cursor_hand(is_hand); + } else { + TW->get_widget().set_cursor_hand(is_hand); + } } void ShowTextEditControl(int x, int y, const std::string &val) { diff --git a/src/platform/w32main.cpp b/src/platform/w32main.cpp index d0837be..0c4d21f 100644 --- a/src/platform/w32main.cpp +++ b/src/platform/w32main.cpp @@ -908,17 +908,12 @@ bool SolveSpace::TextEditControlIsVisible() return IsWindowVisible(TextEditControl) ? true : false; } void SolveSpace::ShowGraphicsEditControl(int x, int y, int fontHeight, int minWidthChars, - const std::string &str) + const std::string &str, bool forDock) { if(GraphicsEditControlIsVisible()) return; - RECT r; - GetClientRect(GraphicsWnd, &r); - x = x + (r.right - r.left)/2; - y = (r.bottom - r.top)/2 - y; - ShowEditControl(GraphicsEditControl, x, y, fontHeight, minWidthChars, - /*isMonospace=*/false, Widen(str)); + /*isMonospace=*/forDock, Widen(str)); } void SolveSpace::HideGraphicsEditControl() { @@ -971,12 +966,6 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam, tme.hwndTrack = GraphicsWnd; TrackMouseEvent(&tme); - // Convert to xy (vs. ij) style coordinates, with (0, 0) at center - RECT r; - GetClientRect(GraphicsWnd, &r); - x = x - (r.right - r.left)/2; - y = (r.bottom - r.top)/2 - y; - LastMousePos.x = x; LastMousePos.y = y; diff --git a/src/render/render.h b/src/render/render.h index 1717f83..00d5ba0 100644 --- a/src/render/render.h +++ b/src/render/render.h @@ -175,7 +175,7 @@ public: virtual void SetCamera(const Camera &camera, bool filp = FLIP_FRAMEBUFFER) = 0; virtual void SetLighting(const Lighting &lighting) = 0; - virtual void NewFrame() = 0; + virtual void NewFrame(int left, int top, int width, int height) = 0; virtual void FlushFrame() = 0; virtual std::shared_ptr ReadFrame() = 0; diff --git a/src/render/rendergl1.cpp b/src/render/rendergl1.cpp index f977daf..54242b3 100644 --- a/src/render/rendergl1.cpp +++ b/src/render/rendergl1.cpp @@ -219,7 +219,7 @@ public: void SetCamera(const Camera &camera, bool filp = FLIP_FRAMEBUFFER) override; void SetLighting(const Lighting &lighting) override; - void NewFrame() override; + void NewFrame(int left, int top, int width, int height) override; void FlushFrame() override; std::shared_ptr ReadFrame() override; @@ -705,8 +705,6 @@ void OpenGl1Renderer::InvalidatePixmap(std::shared_ptr pm) { void OpenGl1Renderer::UpdateProjection(bool flip) { UnSelectPrimitive(); - glViewport(0, 0, camera.width, camera.height); - glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -753,7 +751,11 @@ void OpenGl1Renderer::UpdateProjection(bool flip) { glClear(GL_DEPTH_BUFFER_BIT); } -void OpenGl1Renderer::NewFrame() { +void OpenGl1Renderer::NewFrame(int left, int top, int width, int height) { + glEnable(GL_SCISSOR_TEST); + glScissor(left, top, width, height); + glViewport(left, top, width, height); + glEnable(GL_NORMALIZE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); diff --git a/src/render/rendergl2.cpp b/src/render/rendergl2.cpp index eae9a96..ab72acd 100644 --- a/src/render/rendergl2.cpp +++ b/src/render/rendergl2.cpp @@ -134,7 +134,7 @@ public: void SetCamera(const Camera &c, bool flip) override; void SetLighting(const Lighting &l) override; - void NewFrame() override; + void NewFrame(int left, int top, int width, int height) override; void FlushFrame() override; std::shared_ptr ReadFrame() override; @@ -542,8 +542,6 @@ void OpenGl2Renderer::DrawPixmap(std::shared_ptr pm, } void OpenGl2Renderer::UpdateProjection(bool flip) { - glViewport(0, 0, camera.width, camera.height); - double mat1[16]; double mat2[16]; @@ -611,12 +609,16 @@ void OpenGl2Renderer::UpdateProjection(bool flip) { glClear(GL_DEPTH_BUFFER_BIT); } -void OpenGl2Renderer::NewFrame() { +void OpenGl2Renderer::NewFrame(int left, int top, int width, int height) { if(!initialized) { Init(); initialized = true; } + glEnable(GL_SCISSOR_TEST); + glScissor(left, top, width, height); + glViewport(left, top, width, height); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); diff --git a/src/solvespace.cpp b/src/solvespace.cpp index 50efb5f..52b20ab 100644 --- a/src/solvespace.cpp +++ b/src/solvespace.cpp @@ -102,6 +102,9 @@ void SolveSpaceUI::Init() { RefreshRecentMenus(); // Autosave timer autosaveInterval = CnfThawInt(5, "AutosaveInterval"); + // Single-window UI + GW.dockTextWindow = CnfThawBool(false, "DockTextWindow"); + GW.textDockWidth = CnfThawInt(420, "TextDockWidth"); // The default styles (colors, line widths, etc.) are also stored in the // configuration file, but we will automatically load those as we need @@ -217,6 +220,9 @@ void SolveSpaceUI::Exit() { CnfFreezeBool(showToolbar, "ShowToolbar"); // Autosave timer CnfFreezeInt(autosaveInterval, "AutosaveInterval"); + // Single-window UI + CnfFreezeBool(GW.dockTextWindow, "DockTextWindow"); + CnfFreezeInt(GW.textDockWidth, "TextDockWidth"); // And the default styles, colors and line widths and such. Style::FreezeDefaultStyles(); diff --git a/src/solvespace.h b/src/solvespace.h index faa9bd8..9b9f17a 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -244,7 +244,7 @@ void RadioMenuByCmd(Command id, bool selected); void EnableMenuByCmd(Command id, bool enabled); void ShowGraphicsEditControl(int x, int y, int fontHeight, int minWidthChars, - const std::string &str); + const std::string &str, bool forDock); void HideGraphicsEditControl(); bool GraphicsEditControlIsVisible(); void ShowTextEditControl(int x, int y, const std::string &str); @@ -374,8 +374,10 @@ std::string Basename(std::string filename, bool stripExtension = false); std::string Dirname(std::string filename); bool ReadFile(const std::string &filename, std::string *data); bool WriteFile(const std::string &filename, const std::string &data); + void Message(const char *str, ...); void Error(const char *str, ...); + void CnfFreezeBool(bool v, const std::string &name); void CnfFreezeColor(RgbaColor v, const std::string &name); bool CnfThawBool(bool v, const std::string &name); @@ -749,6 +751,7 @@ public: Unit viewUnits; int afterDecimalMm; int afterDecimalInch; + int autosaveInterval; // in minutes std::string MmToString(double v); diff --git a/src/textwin.cpp b/src/textwin.cpp index 78fafaf..5f15ce3 100644 --- a/src/textwin.cpp +++ b/src/textwin.cpp @@ -251,7 +251,11 @@ void TextWindow::ClearSuper() { void TextWindow::HideEditControl() { editControl.colorPicker.show = false; - HideTextEditControl(); + if(editControl.inDock) { + HideGraphicsEditControl(); + } else { + HideTextEditControl(); + } } void TextWindow::ShowEditControl(int col, const std::string &str, int halfRow) { @@ -262,7 +266,13 @@ void TextWindow::ShowEditControl(int col, const std::string &str, int halfRow) { int x = LEFT_MARGIN + CHAR_WIDTH*col; int y = (halfRow - SS.TW.scrollPos)*(LINE_HEIGHT/2); - ShowTextEditControl(x, y + 18, str); + if(SS.GW.dockTextWindow) { + editControl.inDock = true; + ShowGraphicsEditControl(SS.GW.width + x, y + 18, TextWindow::CHAR_HEIGHT, 30, str, + /*forDock=*/true); + } else { + ShowTextEditControl(x, y + 18, str); + } } void TextWindow::ShowEditControlWithColorPicker(int col, RgbaColor rgb) @@ -510,20 +520,33 @@ void TextWindow::Show() { } } - InvalidateText(); + Invalidate(); +} + +void TextWindow::Invalidate() { + if(SS.GW.dockTextWindow && SS.GW.showTextWindow) { + InvalidateGraphics(); + } else { + InvalidateText(); + } } void TextWindow::TimerCallback() { tooltippedButton = hoveredButton; - InvalidateText(); + Invalidate(); } void TextWindow::DrawOrHitTestIcons(UiCanvas *uiCanvas, TextWindow::DrawOrHitHow how, double mx, double my) { int width, height; - GetTextWindowSize(&width, &height); + if(SS.GW.dockTextWindow) { + GetGraphicsWindowSize(&width, &height); + width = SS.GW.textDockWidth; + } else { + GetTextWindowSize(&width, &height); + } int x = 20, y = 33 + LINE_HEIGHT; y -= scrollPos*(LINE_HEIGHT/2); @@ -562,7 +585,7 @@ void TextWindow::DrawOrHitTestIcons(UiCanvas *uiCanvas, TextWindow::DrawOrHitHow } if(how != PAINT && hoveredButton != oldHovered) { - InvalidateText(); + Invalidate(); } if(tooltippedButton && !tooltippedButton->Tooltip().empty()) { @@ -673,7 +696,7 @@ bool TextWindow::DrawOrHitTestColorPicker(UiCanvas *uiCanvas, DrawOrHitHow how, } if(!editControl.colorPicker.show) return false; - if(how == CLICK || (how == HOVER && leftDown)) InvalidateText(); + if(how == CLICK || (how == HOVER && leftDown)) Invalidate(); static const RgbaColor BaseColor[12] = { RGBi(255, 0, 0), @@ -693,7 +716,13 @@ bool TextWindow::DrawOrHitTestColorPicker(UiCanvas *uiCanvas, DrawOrHitHow how, }; int width, height; - GetTextWindowSize(&width, &height); + if(SS.GW.dockTextWindow) { + GetGraphicsWindowSize(&width, &height); + width = SS.GW.textDockWidth; + } else { + GetTextWindowSize(&width, &height); + } + dbp("%d %d %d %d", width, height, (int)x, (int)y); int px = LEFT_MARGIN + CHAR_WIDTH*editControl.col; int py = (editControl.halfRow - SS.TW.scrollPos)*(LINE_HEIGHT/2); @@ -858,6 +887,11 @@ void TextWindow::Paint() { int width, height; GetTextWindowSize(&width, &height); + Paint(canvas, 0, 0, width, height); +} + +void TextWindow::Paint(std::shared_ptr canvas, + int viewportLeft, int viewportTop, int width, int height) { Camera camera = {}; camera.width = width; camera.height = height; @@ -865,7 +899,7 @@ void TextWindow::Paint() { camera.offset.x = -(double)camera.width / 2.0; camera.offset.y = -(double)camera.height / 2.0; - canvas->NewFrame(); + canvas->NewFrame(viewportLeft, viewportTop, width, height); canvas->SetCamera(camera); UiCanvas uiCanvas = {}; @@ -1062,7 +1096,7 @@ void TextWindow::MouseEvent(bool leftClick, bool leftDown, double x, double y) { prevHoveredCol != hoveredCol) { InvalidateGraphics(); - InvalidateText(); + Invalidate(); } } @@ -1071,7 +1105,7 @@ void TextWindow::MouseLeave() { hoveredButton = NULL; hoveredRow = 0; hoveredCol = 0; - InvalidateText(); + Invalidate(); } void TextWindow::ScrollbarEvent(int newPos) { @@ -1085,7 +1119,7 @@ void TextWindow::ScrollbarEvent(int newPos) { if(newPos != scrollPos) { scrollPos = newPos; MoveTextScrollbarTo(scrollPos, top[rows - 1] + 1, halfRows); - InvalidateText(); + Invalidate(); } } diff --git a/src/ui.h b/src/ui.h index 2ad10b5..75a8588 100644 --- a/src/ui.h +++ b/src/ui.h @@ -203,6 +203,7 @@ public: // These are called by the platform-specific code. void Paint(); + void Paint(std::shared_ptr canvas, int left, int top, int width, int height); void MouseEvent(bool isClick, bool leftDown, double x, double y); void MouseScroll(double x, double y, int delta); void MouseLeave(); @@ -232,6 +233,7 @@ public: void ClearScreen(); void Show(); + void Invalidate(); // State for the screen that we are showing in the text window. enum class Screen : uint32_t { @@ -341,6 +343,8 @@ public: bool picker1dActive; bool picker2dActive; } colorPicker; + + bool inDock; } editControl; void HideEditControl(); @@ -445,6 +449,7 @@ public: static void ScreenChangeExportOffset(int link, uint32_t v); static void ScreenChangeGCodeParameter(int link, uint32_t v); static void ScreenChangeAutosaveInterval(int link, uint32_t v); + static void ScreenChangeTextPaneEnabled(int link, uint32_t v); static void ScreenChangeStyleName(int link, uint32_t v); static void ScreenChangeStyleMetric(int link, uint32_t v); static void ScreenChangeStyleTextAngle(int link, uint32_t v); @@ -715,12 +720,16 @@ public: Command toolbarTooltipped; int toolbarMouseX, toolbarMouseY; + // Text window interaction + bool showTextWindow; + bool dockTextWindow; + double textDockWidth; + // This sets what gets displayed. bool showWorkplanes; bool showNormals; bool showPoints; bool showConstraints; - bool showTextWindow; bool showShaded; bool showEdges; bool showOutlines; @@ -746,8 +755,9 @@ public: // These are called by the platform-specific code. void Paint(); + bool ConvertMouseCoords(double *x, double *y); void MouseMoved(double x, double y, bool leftDown, bool middleDown, - bool rightDown, bool shiftDown, bool ctrlDown); + bool rightDown, bool shiftDown, bool ctrlDown); void MouseLeftDown(double x, double y); void MouseLeftUp(double x, double y); void MouseLeftDoubleClick(double x, double y);