diff --git a/src/cocoa/cocoamain.mm b/src/cocoa/cocoamain.mm index 6a905cc..9931706 100644 --- a/src/cocoa/cocoamain.mm +++ b/src/cocoa/cocoamain.mm @@ -133,7 +133,8 @@ void SolveSpace::ScheduleLater() { @property BOOL wantsBackingStoreScaling; @property(readonly, getter=isEditing) BOOL editing; -- (void)startEditing:(NSString*)text at:(NSPoint)origin; +- (void)startEditing:(NSString*)text at:(NSPoint)origin + withSize:(double)fontSize usingMonospace:(BOOL)isMonospace; - (void)stopEditing; - (void)didEdit:(NSString*)text; @end @@ -160,6 +161,8 @@ void SolveSpace::ScheduleLater() { editor = [[NSTextField alloc] init]; [editor setEditable:YES]; + [[editor cell] setUsesSingleLineMode:YES]; + [editor setBezeled:NO]; [editor setTarget:self]; [editor setAction:@selector(editorAction:)]; @@ -202,7 +205,6 @@ CONVERT(Rect) offscreen = new GLOffscreen; NSSize size = [self convertSizeToBacking:[self bounds].size]; - NSRect bounds = [self convertRectToBacking:[self bounds]]; offscreen->begin(size.width, size.height); [self drawGL]; @@ -225,12 +227,24 @@ CONVERT(Rect) @synthesize editing; -- (void)startEditing:(NSString*)text at:(NSPoint)origin { +- (void)startEditing:(NSString*)text at:(NSPoint)origin + withSize:(double)fontSize usingMonospace:(BOOL)isMonospace { if(!self->editing) { [self addSubview:editor]; self->editing = YES; } + NSFont *font; + if(isMonospace) + font = [NSFont fontWithName:@"Monaco" size:fontSize]; + else + font = [NSFont controlContentFontOfSize:fontSize]; + [editor setFont:font]; + + origin.x -= 3; /* left padding; no way to get it from NSTextField */ + origin.y -= [editor intrinsicContentSize].height; + origin.y += [editor baselineOffsetFromBottom]; + [editor setFrameOrigin:origin]; [editor setStringValue:text]; [self prepareEditor]; @@ -251,9 +265,10 @@ CONVERT(Rect) } - (void)prepareEditor { + CGFloat intrinsicContentHeight = [editor intrinsicContentSize].height; [editor setFrameSize:(NSSize){ - .width = 100, - .height = [editor intrinsicContentSize].height }]; + .width = intrinsicContentHeight * 12, + .height = intrinsicContentHeight }]; } - (void)didEdit:(NSString*)text { @@ -382,18 +397,20 @@ CONVERT(Rect) [super keyDown:event]; } -- (void)startEditing:(NSString*)text at:(NSPoint)xy { +- (void)startEditing:(NSString*)text at:(NSPoint)xy withSize:(double)fontSize { // Convert to ij (vs. xy) style coordinates NSSize size = [self convertSizeToBacking:[self bounds].size]; NSPoint point = { .x = xy.x + size.width / 2, - .y = xy.y - size.height / 2 + [editor intrinsicContentSize].height + .y = xy.y - size.height / 2 }; - [super startEditing:text at:[self convertPointFromBacking:point]]; + [super startEditing:text at:[self convertPointFromBacking:point] + withSize:fontSize usingMonospace:FALSE]; } - (void)didEdit:(NSString*)text { SolveSpace::SS.GW.EditControlDone([text UTF8String]); + [self setNeedsDisplay:YES]; } - (void)cancelOperation:(id)sender { @@ -487,9 +504,10 @@ bool FullScreenIsActive(void) { return [GWDelegate isFullscreen]; } -void ShowGraphicsEditControl(int x, int y, const std::string &str) { +void ShowGraphicsEditControl(int x, int y, int fontSize, const std::string &str) { [GWView startEditing:[NSString stringWithUTF8String:str.c_str()] - at:(NSPoint){(CGFloat)x, (CGFloat)y}]; + at:(NSPoint){(CGFloat)x, (CGFloat)y} + withSize:fontSize]; } void HideGraphicsEditControl(void) { @@ -937,8 +955,8 @@ SolveSpace::DialogChoice SolveSpace::LocateImportedFileYesNoCancel( - (void)startEditing:(NSString*)text at:(NSPoint)point { point = [self convertPointFromBacking:point]; - point.y = -point.y; - [super startEditing:text at:point]; + point.y = -point.y + 2; + [super startEditing:text at:point withSize:15.0 usingMonospace:TRUE]; [[self window] makeKeyWindow]; [[self window] makeFirstResponder:editor]; } diff --git a/src/gtk/gtkmain.cpp b/src/gtk/gtkmain.cpp index f6451c1..2c130f6 100644 --- a/src/gtk/gtkmain.cpp +++ b/src/gtk/gtkmain.cpp @@ -372,24 +372,44 @@ public: EditorOverlay(Gtk::Widget &underlay) : _underlay(underlay) { add(_underlay); - Pango::FontDescription desc; - desc.set_family("monospace"); - desc.set_size(7000); -#ifdef HAVE_GTK3 - _entry.override_font(desc); -#else - _entry.modify_font(desc); -#endif _entry.set_width_chars(30); _entry.set_no_show_all(true); + _entry.set_has_frame(false); add(_entry); _entry.signal_activate(). connect(sigc::mem_fun(this, &EditorOverlay::on_activate)); } - void start_editing(int x, int y, const std::string &val) { - move(_entry, x, y - 4); + void start_editing(int x, int y, int font_height, + bool is_monospace, const std::string &val) { + Pango::FontDescription font_desc; + font_desc.set_family(is_monospace ? "monospace" : "normal"); + font_desc.set_absolute_size(font_height * Pango::SCALE); + +#ifdef HAVE_GTK3 + _entry.override_font(font_desc); +#else + _entry.modify_font(font_desc); +#endif + + /* y coordinate denotes baseline */ + Pango::FontMetrics font_metrics = get_pango_context()->get_metrics(font_desc); + y -= font_metrics.get_ascent() / Pango::SCALE; + +#ifdef HAVE_GTK3 + Gtk::Border border = _entry.get_style_context()->get_padding(); + move(_entry, x - border.get_left(), y - border.get_top()); +#else + /* We need _gtk_entry_effective_inner_border, but it's not + in the public API, so emulate its logic. */ + Gtk::Border border = { 2, 2, 2, 2 }, *style_border; + gtk_widget_style_get(GTK_WIDGET(_entry.gobj()), "inner-border", + &style_border, NULL); + if(style_border) border = *style_border; + move(_entry, x - border.left, y - border.top); +#endif + _entry.set_text(val); if(!_entry.is_visible()) { _entry.show(); @@ -721,16 +741,16 @@ bool FullScreenIsActive(void) { return GW->is_fullscreen(); } -void ShowGraphicsEditControl(int x, int y, const std::string &val) { +void ShowGraphicsEditControl(int x, int y, int fontHeight, 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 - 24; + j = -y + rect.get_height() / 2; - GW->get_overlay().start_editing(i, j, val); + GW->get_overlay().start_editing(i, j, fontHeight, /*is_monospace=*/false, val); } void HideGraphicsEditControl(void) { @@ -1414,7 +1434,8 @@ void SetMousePointerToHand(bool is_hand) { } void ShowTextEditControl(int x, int y, const std::string &val) { - TW->get_overlay().start_editing(x, y, val); + TW->get_overlay().start_editing(x, y, TextWindow::CHAR_HEIGHT, + /*is_monospace=*/true, val); } void HideTextEditControl(void) { diff --git a/src/mouse.cpp b/src/mouse.cpp index ee727c9..ae66dd7 100644 --- a/src/mouse.cpp +++ b/src/mouse.cpp @@ -1292,7 +1292,11 @@ void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) { break; } } - ShowGraphicsEditControl((int)p2.x, (int)p2.y-4, edit_value); + hStyle hs = c->disp.style; + if(hs.v == 0) hs.v = Style::CONSTRAINT; + ShowGraphicsEditControl((int)p2.x, (int)p2.y, + ssglStrFontSize(Style::TextHeight(hs)) * scale, + edit_value); } } diff --git a/src/solvespace.h b/src/solvespace.h index cf2fd9f..1b0c0b8 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -235,7 +235,7 @@ void CheckMenuById(int id, bool checked); void RadioMenuById(int id, bool selected); void EnableMenuById(int id, bool enabled); -void ShowGraphicsEditControl(int x, int y, const std::string &str); +void ShowGraphicsEditControl(int x, int y, int fontHeight, const std::string &str); void HideGraphicsEditControl(void); bool GraphicsEditControlIsVisible(void); void ShowTextEditControl(int x, int y, const std::string &str); diff --git a/src/textwin.cpp b/src/textwin.cpp index e685869..2cb1798 100644 --- a/src/textwin.cpp +++ b/src/textwin.cpp @@ -88,7 +88,7 @@ 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 - 3, y + 2, str); + ShowTextEditControl(x, y + 18, str); } void TextWindow::ShowEditControlWithColorPicker(int col, RgbaColor rgb) diff --git a/src/win32/w32main.cpp b/src/win32/w32main.cpp index 33def55..f8caaf8 100644 --- a/src/win32/w32main.cpp +++ b/src/win32/w32main.cpp @@ -21,10 +21,6 @@ # undef uint32_t // thanks but no thanks #endif -// For the edit controls -#define EDIT_WIDTH 220 -#define EDIT_HEIGHT 21 - HINSTANCE Instance; HWND TextWnd; @@ -803,8 +799,29 @@ void SolveSpace::InvalidateText(void) InvalidateRect(TextWnd, NULL, false); } -static void ShowEditControl(HWND h, int x, int y, const std::wstring &s) { - MoveWindow(h, x, y, EDIT_WIDTH, EDIT_HEIGHT, true); +static void ShowEditControl(HWND h, int x, int y, int fontHeight, + bool isMonospace, const std::wstring &s) { + static HFONT hf; + if(hf) DeleteObject(hf); + hf = CreateFontW(-fontHeight, 0, 0, 0, + FW_REGULAR, false, false, false, ANSI_CHARSET, + OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, FF_DONTCARE, isMonospace ? L"Lucida Console" : L"Arial"); + if(hf) SendMessage(h, WM_SETFONT, (WPARAM)hf, false); + else SendMessage(h, WM_SETFONT, (WPARAM)(HFONT)GetStockObject(SYSTEM_FONT), false); + SendMessage(h, EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN, 0); + + TEXTMETRICW tm; + HDC hdc = GetDC(h); + SelectObject(hdc, hf); + GetTextMetrics(hdc, &tm); + ReleaseDC(h, hdc); + y -= tm.tmAscent; /* y coordinate denotes baseline */ + + RECT rc = { x, y, x + tm.tmAveCharWidth * 30, y + tm.tmHeight }; + AdjustWindowRectEx(&rc, 0, false, WS_EX_CLIENTEDGE); + + MoveWindow(h, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, true); ShowWindow(h, SW_SHOW); if(!s.empty()) { SendMessage(h, WM_SETTEXT, 0, (LPARAM)s.c_str()); @@ -816,7 +833,8 @@ void SolveSpace::ShowTextEditControl(int x, int y, const std::string &str) { if(GraphicsEditControlIsVisible()) return; - ShowEditControl(TextEditControl, x, y, Widen(str)); + ShowEditControl(TextEditControl, x, y, TextWindow::CHAR_HEIGHT, + /*isMonospace=*/true, Widen(str)); } void SolveSpace::HideTextEditControl(void) { @@ -826,7 +844,8 @@ bool SolveSpace::TextEditControlIsVisible(void) { return IsWindowVisible(TextEditControl) ? true : false; } -void SolveSpace::ShowGraphicsEditControl(int x, int y, const std::string &str) +void SolveSpace::ShowGraphicsEditControl(int x, int y, int fontHeight, + const std::string &str) { if(GraphicsEditControlIsVisible()) return; @@ -835,11 +854,8 @@ void SolveSpace::ShowGraphicsEditControl(int x, int y, const std::string &str) x = x + (r.right - r.left)/2; y = (r.bottom - r.top)/2 - y; - // (x, y) are the bottom left, but the edit control is placed by its - // top left corner - y -= 20; - - ShowEditControl(GraphicsEditControl, x, y, Widen(str)); + ShowEditControl(GraphicsEditControl, x, y, fontHeight, + /*isMonospace=*/false, Widen(str)); } void SolveSpace::HideGraphicsEditControl(void) { @@ -1250,7 +1266,6 @@ static void CreateMainWindows(void) GraphicsEditControl = CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDIT, L"", WS_CHILD | ES_AUTOHSCROLL | WS_TABSTOP | WS_CLIPSIBLINGS, 50, 50, 100, 21, GraphicsWnd, NULL, Instance, NULL); - SendMessage(GraphicsEditControl, WM_SETFONT, (WPARAM)FixedFont, true); // The text window, with a comand line and some textual information // about the sketch. @@ -1277,7 +1292,6 @@ static void CreateMainWindows(void) TextEditControl = CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDIT, L"", WS_CHILD | ES_AUTOHSCROLL | WS_TABSTOP | WS_CLIPSIBLINGS, 50, 50, 100, 21, TextWnd, NULL, Instance, NULL); - SendMessage(TextEditControl, WM_SETFONT, (WPARAM)FixedFont, true); // Now that all our windows exist, set up gl contexts. CreateGlContext(TextWnd, &TextGl);