Compare commits

...

1 Commits

Author SHA1 Message Date
whitequark
b7a605c44c Allow docking text window into graphics window.
It can be convenient to dock the text window onto the graphics
window, e.g. for fullscreen support, for window managers that
don't handle two side-by-side windows easily, for ease of dragging,
etc. Also, emscripten only provides access to one OpenGL context,
so it's a requirement for a WebGL port.

This isn't yet fully usable: it misses scrollbar support, and
there is no way to resize the dock.
2016-11-19 21:52:42 +00:00
14 changed files with 228 additions and 151 deletions

View File

@ -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);

View File

@ -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());

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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]];

View File

@ -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<Gdk::Window> 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) {

View File

@ -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;

View File

@ -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<Pixmap> ReadFrame() = 0;

View File

@ -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<Pixmap> ReadFrame() override;
@ -705,8 +705,6 @@ void OpenGl1Renderer::InvalidatePixmap(std::shared_ptr<const Pixmap> 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);

View File

@ -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<Pixmap> ReadFrame() override;
@ -542,8 +542,6 @@ void OpenGl2Renderer::DrawPixmap(std::shared_ptr<const Pixmap> 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);

View File

@ -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();

View File

@ -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);

View File

@ -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<ViewportCanvas> 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();
}
}

View File

@ -203,6 +203,7 @@ public:
// These are called by the platform-specific code.
void Paint();
void Paint(std::shared_ptr<ViewportCanvas> 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);