1*d7f7bf2dSAxel Dörfler /* 2*d7f7bf2dSAxel Dörfler * Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>. 3*d7f7bf2dSAxel Dörfler * All rights reserved. Distributed under the terms of the MIT License. 4*d7f7bf2dSAxel Dörfler */ 5*d7f7bf2dSAxel Dörfler 6*d7f7bf2dSAxel Dörfler #include "TextDocumentView.h" 7*d7f7bf2dSAxel Dörfler 8*d7f7bf2dSAxel Dörfler #include <algorithm> 9*d7f7bf2dSAxel Dörfler #include <stdio.h> 10*d7f7bf2dSAxel Dörfler 11*d7f7bf2dSAxel Dörfler #include <Clipboard.h> 12*d7f7bf2dSAxel Dörfler #include <Cursor.h> 13*d7f7bf2dSAxel Dörfler #include <ScrollBar.h> 14*d7f7bf2dSAxel Dörfler #include <Shape.h> 15*d7f7bf2dSAxel Dörfler #include <Window.h> 16*d7f7bf2dSAxel Dörfler 17*d7f7bf2dSAxel Dörfler 18*d7f7bf2dSAxel Dörfler TextDocumentView::TextDocumentView(const char* name) 19*d7f7bf2dSAxel Dörfler : 20*d7f7bf2dSAxel Dörfler BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS 21*d7f7bf2dSAxel Dörfler | B_PULSE_NEEDED), 22*d7f7bf2dSAxel Dörfler fInsetLeft(0.0f), 23*d7f7bf2dSAxel Dörfler fInsetTop(0.0f), 24*d7f7bf2dSAxel Dörfler fInsetRight(0.0f), 25*d7f7bf2dSAxel Dörfler fInsetBottom(0.0f), 26*d7f7bf2dSAxel Dörfler 27*d7f7bf2dSAxel Dörfler fCaretBounds(), 28*d7f7bf2dSAxel Dörfler fShowCaret(false), 29*d7f7bf2dSAxel Dörfler fMouseDown(false) 30*d7f7bf2dSAxel Dörfler { 31*d7f7bf2dSAxel Dörfler fTextDocumentLayout.SetWidth(_TextLayoutWidth(Bounds().Width())); 32*d7f7bf2dSAxel Dörfler 33*d7f7bf2dSAxel Dörfler // Set default TextEditor 34*d7f7bf2dSAxel Dörfler SetTextEditor(TextEditorRef(new(std::nothrow) TextEditor(), true)); 35*d7f7bf2dSAxel Dörfler 36*d7f7bf2dSAxel Dörfler SetViewColor(B_TRANSPARENT_COLOR); 37*d7f7bf2dSAxel Dörfler SetLowColor(255, 255, 255, 255); 38*d7f7bf2dSAxel Dörfler } 39*d7f7bf2dSAxel Dörfler 40*d7f7bf2dSAxel Dörfler 41*d7f7bf2dSAxel Dörfler TextDocumentView::~TextDocumentView() 42*d7f7bf2dSAxel Dörfler { 43*d7f7bf2dSAxel Dörfler // Don't forget to remove listeners 44*d7f7bf2dSAxel Dörfler SetTextEditor(TextEditorRef()); 45*d7f7bf2dSAxel Dörfler } 46*d7f7bf2dSAxel Dörfler 47*d7f7bf2dSAxel Dörfler 48*d7f7bf2dSAxel Dörfler void 49*d7f7bf2dSAxel Dörfler TextDocumentView::MessageReceived(BMessage* message) 50*d7f7bf2dSAxel Dörfler { 51*d7f7bf2dSAxel Dörfler switch (message->what) { 52*d7f7bf2dSAxel Dörfler case B_COPY: 53*d7f7bf2dSAxel Dörfler Copy(be_clipboard); 54*d7f7bf2dSAxel Dörfler break; 55*d7f7bf2dSAxel Dörfler 56*d7f7bf2dSAxel Dörfler default: 57*d7f7bf2dSAxel Dörfler BView::MessageReceived(message); 58*d7f7bf2dSAxel Dörfler } 59*d7f7bf2dSAxel Dörfler } 60*d7f7bf2dSAxel Dörfler 61*d7f7bf2dSAxel Dörfler 62*d7f7bf2dSAxel Dörfler void 63*d7f7bf2dSAxel Dörfler TextDocumentView::Draw(BRect updateRect) 64*d7f7bf2dSAxel Dörfler { 65*d7f7bf2dSAxel Dörfler FillRect(updateRect, B_SOLID_LOW); 66*d7f7bf2dSAxel Dörfler 67*d7f7bf2dSAxel Dörfler fTextDocumentLayout.SetWidth(_TextLayoutWidth(Bounds().Width())); 68*d7f7bf2dSAxel Dörfler fTextDocumentLayout.Draw(this, BPoint(fInsetLeft, fInsetTop), updateRect); 69*d7f7bf2dSAxel Dörfler 70*d7f7bf2dSAxel Dörfler if (fTextEditor.Get() == NULL) 71*d7f7bf2dSAxel Dörfler return; 72*d7f7bf2dSAxel Dörfler 73*d7f7bf2dSAxel Dörfler bool isCaret = fTextEditor->SelectionLength() == 0; 74*d7f7bf2dSAxel Dörfler 75*d7f7bf2dSAxel Dörfler if (isCaret) { 76*d7f7bf2dSAxel Dörfler if (fShowCaret && fTextEditor->IsEditingEnabled()) 77*d7f7bf2dSAxel Dörfler _DrawCaret(fTextEditor->CaretOffset()); 78*d7f7bf2dSAxel Dörfler } else { 79*d7f7bf2dSAxel Dörfler _DrawSelection(); 80*d7f7bf2dSAxel Dörfler } 81*d7f7bf2dSAxel Dörfler } 82*d7f7bf2dSAxel Dörfler 83*d7f7bf2dSAxel Dörfler 84*d7f7bf2dSAxel Dörfler void 85*d7f7bf2dSAxel Dörfler TextDocumentView::Pulse() 86*d7f7bf2dSAxel Dörfler { 87*d7f7bf2dSAxel Dörfler if (fTextEditor.Get() == NULL) 88*d7f7bf2dSAxel Dörfler return; 89*d7f7bf2dSAxel Dörfler 90*d7f7bf2dSAxel Dörfler // Blink cursor 91*d7f7bf2dSAxel Dörfler fShowCaret = !fShowCaret; 92*d7f7bf2dSAxel Dörfler if (fCaretBounds.IsValid()) 93*d7f7bf2dSAxel Dörfler Invalidate(fCaretBounds); 94*d7f7bf2dSAxel Dörfler else 95*d7f7bf2dSAxel Dörfler Invalidate(); 96*d7f7bf2dSAxel Dörfler } 97*d7f7bf2dSAxel Dörfler 98*d7f7bf2dSAxel Dörfler 99*d7f7bf2dSAxel Dörfler void 100*d7f7bf2dSAxel Dörfler TextDocumentView::AttachedToWindow() 101*d7f7bf2dSAxel Dörfler { 102*d7f7bf2dSAxel Dörfler _UpdateScrollBars(); 103*d7f7bf2dSAxel Dörfler } 104*d7f7bf2dSAxel Dörfler 105*d7f7bf2dSAxel Dörfler 106*d7f7bf2dSAxel Dörfler void 107*d7f7bf2dSAxel Dörfler TextDocumentView::FrameResized(float width, float height) 108*d7f7bf2dSAxel Dörfler { 109*d7f7bf2dSAxel Dörfler fTextDocumentLayout.SetWidth(width); 110*d7f7bf2dSAxel Dörfler _UpdateScrollBars(); 111*d7f7bf2dSAxel Dörfler } 112*d7f7bf2dSAxel Dörfler 113*d7f7bf2dSAxel Dörfler 114*d7f7bf2dSAxel Dörfler void 115*d7f7bf2dSAxel Dörfler TextDocumentView::WindowActivated(bool active) 116*d7f7bf2dSAxel Dörfler { 117*d7f7bf2dSAxel Dörfler Invalidate(); 118*d7f7bf2dSAxel Dörfler } 119*d7f7bf2dSAxel Dörfler 120*d7f7bf2dSAxel Dörfler 121*d7f7bf2dSAxel Dörfler void 122*d7f7bf2dSAxel Dörfler TextDocumentView::MakeFocus(bool focus) 123*d7f7bf2dSAxel Dörfler { 124*d7f7bf2dSAxel Dörfler if (focus != IsFocus()) 125*d7f7bf2dSAxel Dörfler Invalidate(); 126*d7f7bf2dSAxel Dörfler BView::MakeFocus(focus); 127*d7f7bf2dSAxel Dörfler } 128*d7f7bf2dSAxel Dörfler 129*d7f7bf2dSAxel Dörfler 130*d7f7bf2dSAxel Dörfler void 131*d7f7bf2dSAxel Dörfler TextDocumentView::MouseDown(BPoint where) 132*d7f7bf2dSAxel Dörfler { 133*d7f7bf2dSAxel Dörfler MakeFocus(); 134*d7f7bf2dSAxel Dörfler 135*d7f7bf2dSAxel Dörfler int32 modifiers = 0; 136*d7f7bf2dSAxel Dörfler if (Window() != NULL && Window()->CurrentMessage() != NULL) 137*d7f7bf2dSAxel Dörfler Window()->CurrentMessage()->FindInt32("modifiers", &modifiers); 138*d7f7bf2dSAxel Dörfler 139*d7f7bf2dSAxel Dörfler fMouseDown = true; 140*d7f7bf2dSAxel Dörfler SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); 141*d7f7bf2dSAxel Dörfler 142*d7f7bf2dSAxel Dörfler bool extendSelection = (modifiers & B_SHIFT_KEY) != 0; 143*d7f7bf2dSAxel Dörfler SetCaret(where, extendSelection); 144*d7f7bf2dSAxel Dörfler } 145*d7f7bf2dSAxel Dörfler 146*d7f7bf2dSAxel Dörfler 147*d7f7bf2dSAxel Dörfler void 148*d7f7bf2dSAxel Dörfler TextDocumentView::MouseUp(BPoint where) 149*d7f7bf2dSAxel Dörfler { 150*d7f7bf2dSAxel Dörfler fMouseDown = false; 151*d7f7bf2dSAxel Dörfler } 152*d7f7bf2dSAxel Dörfler 153*d7f7bf2dSAxel Dörfler 154*d7f7bf2dSAxel Dörfler void 155*d7f7bf2dSAxel Dörfler TextDocumentView::MouseMoved(BPoint where, uint32 transit, 156*d7f7bf2dSAxel Dörfler const BMessage* dragMessage) 157*d7f7bf2dSAxel Dörfler { 158*d7f7bf2dSAxel Dörfler BCursor iBeamCursor(B_CURSOR_ID_I_BEAM); 159*d7f7bf2dSAxel Dörfler SetViewCursor(&iBeamCursor); 160*d7f7bf2dSAxel Dörfler 161*d7f7bf2dSAxel Dörfler if (fMouseDown) 162*d7f7bf2dSAxel Dörfler SetCaret(where, true); 163*d7f7bf2dSAxel Dörfler } 164*d7f7bf2dSAxel Dörfler 165*d7f7bf2dSAxel Dörfler 166*d7f7bf2dSAxel Dörfler void 167*d7f7bf2dSAxel Dörfler TextDocumentView::KeyDown(const char* bytes, int32 numBytes) 168*d7f7bf2dSAxel Dörfler { 169*d7f7bf2dSAxel Dörfler if (fTextEditor.Get() == NULL) 170*d7f7bf2dSAxel Dörfler return; 171*d7f7bf2dSAxel Dörfler 172*d7f7bf2dSAxel Dörfler KeyEvent event; 173*d7f7bf2dSAxel Dörfler event.bytes = bytes; 174*d7f7bf2dSAxel Dörfler event.length = numBytes; 175*d7f7bf2dSAxel Dörfler event.key = 0; 176*d7f7bf2dSAxel Dörfler event.modifiers = modifiers(); 177*d7f7bf2dSAxel Dörfler 178*d7f7bf2dSAxel Dörfler if (Window() != NULL && Window()->CurrentMessage() != NULL) { 179*d7f7bf2dSAxel Dörfler BMessage* message = Window()->CurrentMessage(); 180*d7f7bf2dSAxel Dörfler message->FindInt32("raw_char", &event.key); 181*d7f7bf2dSAxel Dörfler message->FindInt32("modifiers", &event.modifiers); 182*d7f7bf2dSAxel Dörfler } 183*d7f7bf2dSAxel Dörfler 184*d7f7bf2dSAxel Dörfler fTextEditor->KeyDown(event); 185*d7f7bf2dSAxel Dörfler fShowCaret = true; 186*d7f7bf2dSAxel Dörfler Invalidate(); 187*d7f7bf2dSAxel Dörfler } 188*d7f7bf2dSAxel Dörfler 189*d7f7bf2dSAxel Dörfler 190*d7f7bf2dSAxel Dörfler void 191*d7f7bf2dSAxel Dörfler TextDocumentView::KeyUp(const char* bytes, int32 numBytes) 192*d7f7bf2dSAxel Dörfler { 193*d7f7bf2dSAxel Dörfler } 194*d7f7bf2dSAxel Dörfler 195*d7f7bf2dSAxel Dörfler 196*d7f7bf2dSAxel Dörfler BSize 197*d7f7bf2dSAxel Dörfler TextDocumentView::MinSize() 198*d7f7bf2dSAxel Dörfler { 199*d7f7bf2dSAxel Dörfler return BSize(fInsetLeft + fInsetRight + 50.0f, fInsetTop + fInsetBottom); 200*d7f7bf2dSAxel Dörfler } 201*d7f7bf2dSAxel Dörfler 202*d7f7bf2dSAxel Dörfler 203*d7f7bf2dSAxel Dörfler BSize 204*d7f7bf2dSAxel Dörfler TextDocumentView::MaxSize() 205*d7f7bf2dSAxel Dörfler { 206*d7f7bf2dSAxel Dörfler return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED); 207*d7f7bf2dSAxel Dörfler } 208*d7f7bf2dSAxel Dörfler 209*d7f7bf2dSAxel Dörfler 210*d7f7bf2dSAxel Dörfler BSize 211*d7f7bf2dSAxel Dörfler TextDocumentView::PreferredSize() 212*d7f7bf2dSAxel Dörfler { 213*d7f7bf2dSAxel Dörfler return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED); 214*d7f7bf2dSAxel Dörfler } 215*d7f7bf2dSAxel Dörfler 216*d7f7bf2dSAxel Dörfler 217*d7f7bf2dSAxel Dörfler bool 218*d7f7bf2dSAxel Dörfler TextDocumentView::HasHeightForWidth() 219*d7f7bf2dSAxel Dörfler { 220*d7f7bf2dSAxel Dörfler return true; 221*d7f7bf2dSAxel Dörfler } 222*d7f7bf2dSAxel Dörfler 223*d7f7bf2dSAxel Dörfler 224*d7f7bf2dSAxel Dörfler void 225*d7f7bf2dSAxel Dörfler TextDocumentView::GetHeightForWidth(float width, float* min, float* max, 226*d7f7bf2dSAxel Dörfler float* preferred) 227*d7f7bf2dSAxel Dörfler { 228*d7f7bf2dSAxel Dörfler TextDocumentLayout layout(fTextDocumentLayout); 229*d7f7bf2dSAxel Dörfler layout.SetWidth(_TextLayoutWidth(width)); 230*d7f7bf2dSAxel Dörfler 231*d7f7bf2dSAxel Dörfler float height = layout.Height() + 1 + fInsetTop + fInsetBottom; 232*d7f7bf2dSAxel Dörfler 233*d7f7bf2dSAxel Dörfler if (min != NULL) 234*d7f7bf2dSAxel Dörfler *min = height; 235*d7f7bf2dSAxel Dörfler if (max != NULL) 236*d7f7bf2dSAxel Dörfler *max = height; 237*d7f7bf2dSAxel Dörfler if (preferred != NULL) 238*d7f7bf2dSAxel Dörfler *preferred = height; 239*d7f7bf2dSAxel Dörfler } 240*d7f7bf2dSAxel Dörfler 241*d7f7bf2dSAxel Dörfler 242*d7f7bf2dSAxel Dörfler // #pragma mark - 243*d7f7bf2dSAxel Dörfler 244*d7f7bf2dSAxel Dörfler 245*d7f7bf2dSAxel Dörfler void 246*d7f7bf2dSAxel Dörfler TextDocumentView::SetTextDocument(const TextDocumentRef& document) 247*d7f7bf2dSAxel Dörfler { 248*d7f7bf2dSAxel Dörfler fTextDocument = document; 249*d7f7bf2dSAxel Dörfler fTextDocumentLayout.SetTextDocument(fTextDocument); 250*d7f7bf2dSAxel Dörfler if (fTextEditor.Get() != NULL) 251*d7f7bf2dSAxel Dörfler fTextEditor->SetDocument(document); 252*d7f7bf2dSAxel Dörfler 253*d7f7bf2dSAxel Dörfler InvalidateLayout(); 254*d7f7bf2dSAxel Dörfler Invalidate(); 255*d7f7bf2dSAxel Dörfler _UpdateScrollBars(); 256*d7f7bf2dSAxel Dörfler } 257*d7f7bf2dSAxel Dörfler 258*d7f7bf2dSAxel Dörfler 259*d7f7bf2dSAxel Dörfler void 260*d7f7bf2dSAxel Dörfler TextDocumentView::SetEditingEnabled(bool enabled) 261*d7f7bf2dSAxel Dörfler { 262*d7f7bf2dSAxel Dörfler if (fTextEditor.Get() != NULL) 263*d7f7bf2dSAxel Dörfler fTextEditor->SetEditingEnabled(enabled); 264*d7f7bf2dSAxel Dörfler } 265*d7f7bf2dSAxel Dörfler 266*d7f7bf2dSAxel Dörfler 267*d7f7bf2dSAxel Dörfler void 268*d7f7bf2dSAxel Dörfler TextDocumentView::SetTextEditor(const TextEditorRef& editor) 269*d7f7bf2dSAxel Dörfler { 270*d7f7bf2dSAxel Dörfler if (fTextEditor == editor) 271*d7f7bf2dSAxel Dörfler return; 272*d7f7bf2dSAxel Dörfler 273*d7f7bf2dSAxel Dörfler if (fTextEditor.Get() != NULL) { 274*d7f7bf2dSAxel Dörfler fTextEditor->SetDocument(TextDocumentRef()); 275*d7f7bf2dSAxel Dörfler fTextEditor->SetLayout(TextDocumentLayoutRef()); 276*d7f7bf2dSAxel Dörfler // TODO: Probably has to remove listeners 277*d7f7bf2dSAxel Dörfler } 278*d7f7bf2dSAxel Dörfler 279*d7f7bf2dSAxel Dörfler fTextEditor = editor; 280*d7f7bf2dSAxel Dörfler 281*d7f7bf2dSAxel Dörfler if (fTextEditor.Get() != NULL) { 282*d7f7bf2dSAxel Dörfler fTextEditor->SetDocument(fTextDocument); 283*d7f7bf2dSAxel Dörfler fTextEditor->SetLayout(TextDocumentLayoutRef( 284*d7f7bf2dSAxel Dörfler &fTextDocumentLayout)); 285*d7f7bf2dSAxel Dörfler // TODO: Probably has to add listeners 286*d7f7bf2dSAxel Dörfler } 287*d7f7bf2dSAxel Dörfler } 288*d7f7bf2dSAxel Dörfler 289*d7f7bf2dSAxel Dörfler 290*d7f7bf2dSAxel Dörfler void 291*d7f7bf2dSAxel Dörfler TextDocumentView::SetInsets(float inset) 292*d7f7bf2dSAxel Dörfler { 293*d7f7bf2dSAxel Dörfler SetInsets(inset, inset, inset, inset); 294*d7f7bf2dSAxel Dörfler } 295*d7f7bf2dSAxel Dörfler 296*d7f7bf2dSAxel Dörfler 297*d7f7bf2dSAxel Dörfler void 298*d7f7bf2dSAxel Dörfler TextDocumentView::SetInsets(float horizontal, float vertical) 299*d7f7bf2dSAxel Dörfler { 300*d7f7bf2dSAxel Dörfler SetInsets(horizontal, vertical, horizontal, vertical); 301*d7f7bf2dSAxel Dörfler } 302*d7f7bf2dSAxel Dörfler 303*d7f7bf2dSAxel Dörfler 304*d7f7bf2dSAxel Dörfler void 305*d7f7bf2dSAxel Dörfler TextDocumentView::SetInsets(float left, float top, float right, float bottom) 306*d7f7bf2dSAxel Dörfler { 307*d7f7bf2dSAxel Dörfler if (fInsetLeft == left && fInsetTop == top 308*d7f7bf2dSAxel Dörfler && fInsetRight == right && fInsetBottom == bottom) { 309*d7f7bf2dSAxel Dörfler return; 310*d7f7bf2dSAxel Dörfler } 311*d7f7bf2dSAxel Dörfler 312*d7f7bf2dSAxel Dörfler fInsetLeft = left; 313*d7f7bf2dSAxel Dörfler fInsetTop = top; 314*d7f7bf2dSAxel Dörfler fInsetRight = right; 315*d7f7bf2dSAxel Dörfler fInsetBottom = bottom; 316*d7f7bf2dSAxel Dörfler 317*d7f7bf2dSAxel Dörfler InvalidateLayout(); 318*d7f7bf2dSAxel Dörfler Invalidate(); 319*d7f7bf2dSAxel Dörfler } 320*d7f7bf2dSAxel Dörfler 321*d7f7bf2dSAxel Dörfler 322*d7f7bf2dSAxel Dörfler void 323*d7f7bf2dSAxel Dörfler TextDocumentView::SetCaret(BPoint location, bool extendSelection) 324*d7f7bf2dSAxel Dörfler { 325*d7f7bf2dSAxel Dörfler if (fTextEditor.Get() == NULL) 326*d7f7bf2dSAxel Dörfler return; 327*d7f7bf2dSAxel Dörfler 328*d7f7bf2dSAxel Dörfler location.x -= fInsetLeft; 329*d7f7bf2dSAxel Dörfler location.y -= fInsetTop; 330*d7f7bf2dSAxel Dörfler 331*d7f7bf2dSAxel Dörfler fTextEditor->SetCaret(location, extendSelection); 332*d7f7bf2dSAxel Dörfler fShowCaret = !extendSelection; 333*d7f7bf2dSAxel Dörfler Invalidate(); 334*d7f7bf2dSAxel Dörfler } 335*d7f7bf2dSAxel Dörfler 336*d7f7bf2dSAxel Dörfler 337*d7f7bf2dSAxel Dörfler bool 338*d7f7bf2dSAxel Dörfler TextDocumentView::HasSelection() const 339*d7f7bf2dSAxel Dörfler { 340*d7f7bf2dSAxel Dörfler return fTextEditor.Get() != NULL && fTextEditor->HasSelection(); 341*d7f7bf2dSAxel Dörfler } 342*d7f7bf2dSAxel Dörfler 343*d7f7bf2dSAxel Dörfler 344*d7f7bf2dSAxel Dörfler void 345*d7f7bf2dSAxel Dörfler TextDocumentView::GetSelection(int32& start, int32& end) const 346*d7f7bf2dSAxel Dörfler { 347*d7f7bf2dSAxel Dörfler if (fTextEditor.Get()) { 348*d7f7bf2dSAxel Dörfler start = fTextEditor->SelectionStart(); 349*d7f7bf2dSAxel Dörfler end = fTextEditor->SelectionEnd(); 350*d7f7bf2dSAxel Dörfler } 351*d7f7bf2dSAxel Dörfler } 352*d7f7bf2dSAxel Dörfler 353*d7f7bf2dSAxel Dörfler 354*d7f7bf2dSAxel Dörfler void 355*d7f7bf2dSAxel Dörfler TextDocumentView::Copy(BClipboard* clipboard) 356*d7f7bf2dSAxel Dörfler { 357*d7f7bf2dSAxel Dörfler if (!HasSelection() || fTextDocument.Get() == NULL) { 358*d7f7bf2dSAxel Dörfler // Nothing to copy, don't clear clipboard contents for now reason. 359*d7f7bf2dSAxel Dörfler return; 360*d7f7bf2dSAxel Dörfler } 361*d7f7bf2dSAxel Dörfler 362*d7f7bf2dSAxel Dörfler if (clipboard == NULL || !clipboard->Lock()) 363*d7f7bf2dSAxel Dörfler return; 364*d7f7bf2dSAxel Dörfler 365*d7f7bf2dSAxel Dörfler clipboard->Clear(); 366*d7f7bf2dSAxel Dörfler 367*d7f7bf2dSAxel Dörfler BMessage* clip = clipboard->Data(); 368*d7f7bf2dSAxel Dörfler if (clip != NULL) { 369*d7f7bf2dSAxel Dörfler int32 start; 370*d7f7bf2dSAxel Dörfler int32 end; 371*d7f7bf2dSAxel Dörfler GetSelection(start, end); 372*d7f7bf2dSAxel Dörfler 373*d7f7bf2dSAxel Dörfler BString text = fTextDocument->Text(start, end - start); 374*d7f7bf2dSAxel Dörfler clip->AddData("text/plain", B_MIME_TYPE, text.String(), 375*d7f7bf2dSAxel Dörfler text.Length()); 376*d7f7bf2dSAxel Dörfler 377*d7f7bf2dSAxel Dörfler // TODO: Support for "application/x-vnd.Be-text_run_array" 378*d7f7bf2dSAxel Dörfler 379*d7f7bf2dSAxel Dörfler clipboard->Commit(); 380*d7f7bf2dSAxel Dörfler } 381*d7f7bf2dSAxel Dörfler 382*d7f7bf2dSAxel Dörfler clipboard->Unlock(); 383*d7f7bf2dSAxel Dörfler } 384*d7f7bf2dSAxel Dörfler 385*d7f7bf2dSAxel Dörfler 386*d7f7bf2dSAxel Dörfler // #pragma mark - private 387*d7f7bf2dSAxel Dörfler 388*d7f7bf2dSAxel Dörfler 389*d7f7bf2dSAxel Dörfler float 390*d7f7bf2dSAxel Dörfler TextDocumentView::_TextLayoutWidth(float viewWidth) const 391*d7f7bf2dSAxel Dörfler { 392*d7f7bf2dSAxel Dörfler return viewWidth - (fInsetLeft + fInsetRight); 393*d7f7bf2dSAxel Dörfler } 394*d7f7bf2dSAxel Dörfler 395*d7f7bf2dSAxel Dörfler 396*d7f7bf2dSAxel Dörfler static const float kHorizontalScrollBarStep = 10.0f; 397*d7f7bf2dSAxel Dörfler static const float kVerticalScrollBarStep = 12.0f; 398*d7f7bf2dSAxel Dörfler 399*d7f7bf2dSAxel Dörfler 400*d7f7bf2dSAxel Dörfler void 401*d7f7bf2dSAxel Dörfler TextDocumentView::_UpdateScrollBars() 402*d7f7bf2dSAxel Dörfler { 403*d7f7bf2dSAxel Dörfler BRect bounds(Bounds()); 404*d7f7bf2dSAxel Dörfler 405*d7f7bf2dSAxel Dörfler BScrollBar* horizontalScrollBar = ScrollBar(B_HORIZONTAL); 406*d7f7bf2dSAxel Dörfler if (horizontalScrollBar != NULL) { 407*d7f7bf2dSAxel Dörfler long viewWidth = bounds.IntegerWidth(); 408*d7f7bf2dSAxel Dörfler long dataWidth = (long)ceilf( 409*d7f7bf2dSAxel Dörfler fTextDocumentLayout.Width() + fInsetLeft + fInsetRight); 410*d7f7bf2dSAxel Dörfler 411*d7f7bf2dSAxel Dörfler long maxRange = dataWidth - viewWidth; 412*d7f7bf2dSAxel Dörfler maxRange = std::max(maxRange, 0L); 413*d7f7bf2dSAxel Dörfler 414*d7f7bf2dSAxel Dörfler horizontalScrollBar->SetRange(0, (float)maxRange); 415*d7f7bf2dSAxel Dörfler horizontalScrollBar->SetProportion((float)viewWidth / dataWidth); 416*d7f7bf2dSAxel Dörfler horizontalScrollBar->SetSteps(kHorizontalScrollBarStep, dataWidth / 10); 417*d7f7bf2dSAxel Dörfler } 418*d7f7bf2dSAxel Dörfler 419*d7f7bf2dSAxel Dörfler BScrollBar* verticalScrollBar = ScrollBar(B_VERTICAL); 420*d7f7bf2dSAxel Dörfler if (verticalScrollBar != NULL) { 421*d7f7bf2dSAxel Dörfler long viewHeight = bounds.IntegerHeight(); 422*d7f7bf2dSAxel Dörfler long dataHeight = (long)ceilf( 423*d7f7bf2dSAxel Dörfler fTextDocumentLayout.Height() + fInsetTop + fInsetBottom); 424*d7f7bf2dSAxel Dörfler 425*d7f7bf2dSAxel Dörfler long maxRange = dataHeight - viewHeight; 426*d7f7bf2dSAxel Dörfler maxRange = std::max(maxRange, 0L); 427*d7f7bf2dSAxel Dörfler 428*d7f7bf2dSAxel Dörfler verticalScrollBar->SetRange(0, maxRange); 429*d7f7bf2dSAxel Dörfler verticalScrollBar->SetProportion((float)viewHeight / dataHeight); 430*d7f7bf2dSAxel Dörfler verticalScrollBar->SetSteps(kVerticalScrollBarStep, viewHeight); 431*d7f7bf2dSAxel Dörfler } 432*d7f7bf2dSAxel Dörfler } 433*d7f7bf2dSAxel Dörfler 434*d7f7bf2dSAxel Dörfler 435*d7f7bf2dSAxel Dörfler void 436*d7f7bf2dSAxel Dörfler TextDocumentView::_DrawCaret(int32 textOffset) 437*d7f7bf2dSAxel Dörfler { 438*d7f7bf2dSAxel Dörfler if (!IsFocus() || Window() == NULL || !Window()->IsActive()) 439*d7f7bf2dSAxel Dörfler return; 440*d7f7bf2dSAxel Dörfler 441*d7f7bf2dSAxel Dörfler float x1; 442*d7f7bf2dSAxel Dörfler float y1; 443*d7f7bf2dSAxel Dörfler float x2; 444*d7f7bf2dSAxel Dörfler float y2; 445*d7f7bf2dSAxel Dörfler 446*d7f7bf2dSAxel Dörfler fTextDocumentLayout.GetTextBounds(textOffset, x1, y1, x2, y2); 447*d7f7bf2dSAxel Dörfler x2 = x1 + 1; 448*d7f7bf2dSAxel Dörfler 449*d7f7bf2dSAxel Dörfler fCaretBounds = BRect(x1, y1, x2, y2); 450*d7f7bf2dSAxel Dörfler fCaretBounds.OffsetBy(fInsetLeft, fInsetTop); 451*d7f7bf2dSAxel Dörfler 452*d7f7bf2dSAxel Dörfler SetDrawingMode(B_OP_INVERT); 453*d7f7bf2dSAxel Dörfler FillRect(fCaretBounds); 454*d7f7bf2dSAxel Dörfler } 455*d7f7bf2dSAxel Dörfler 456*d7f7bf2dSAxel Dörfler 457*d7f7bf2dSAxel Dörfler void 458*d7f7bf2dSAxel Dörfler TextDocumentView::_DrawSelection() 459*d7f7bf2dSAxel Dörfler { 460*d7f7bf2dSAxel Dörfler int32 start; 461*d7f7bf2dSAxel Dörfler int32 end; 462*d7f7bf2dSAxel Dörfler GetSelection(start, end); 463*d7f7bf2dSAxel Dörfler 464*d7f7bf2dSAxel Dörfler BShape shape; 465*d7f7bf2dSAxel Dörfler _GetSelectionShape(shape, start, end); 466*d7f7bf2dSAxel Dörfler 467*d7f7bf2dSAxel Dörfler SetDrawingMode(B_OP_SUBTRACT); 468*d7f7bf2dSAxel Dörfler 469*d7f7bf2dSAxel Dörfler SetLineMode(B_ROUND_CAP, B_ROUND_JOIN); 470*d7f7bf2dSAxel Dörfler MovePenTo(fInsetLeft - 0.5f, fInsetTop - 0.5f); 471*d7f7bf2dSAxel Dörfler 472*d7f7bf2dSAxel Dörfler if (IsFocus() && Window() != NULL && Window()->IsActive()) { 473*d7f7bf2dSAxel Dörfler SetHighColor(30, 30, 30); 474*d7f7bf2dSAxel Dörfler FillShape(&shape); 475*d7f7bf2dSAxel Dörfler } 476*d7f7bf2dSAxel Dörfler 477*d7f7bf2dSAxel Dörfler SetHighColor(40, 40, 40); 478*d7f7bf2dSAxel Dörfler StrokeShape(&shape); 479*d7f7bf2dSAxel Dörfler } 480*d7f7bf2dSAxel Dörfler 481*d7f7bf2dSAxel Dörfler 482*d7f7bf2dSAxel Dörfler void 483*d7f7bf2dSAxel Dörfler TextDocumentView::_GetSelectionShape(BShape& shape, int32 start, int32 end) 484*d7f7bf2dSAxel Dörfler { 485*d7f7bf2dSAxel Dörfler float startX1; 486*d7f7bf2dSAxel Dörfler float startY1; 487*d7f7bf2dSAxel Dörfler float startX2; 488*d7f7bf2dSAxel Dörfler float startY2; 489*d7f7bf2dSAxel Dörfler fTextDocumentLayout.GetTextBounds(start, startX1, startY1, startX2, 490*d7f7bf2dSAxel Dörfler startY2); 491*d7f7bf2dSAxel Dörfler 492*d7f7bf2dSAxel Dörfler startX1 = floorf(startX1); 493*d7f7bf2dSAxel Dörfler startY1 = floorf(startY1); 494*d7f7bf2dSAxel Dörfler startX2 = ceilf(startX2); 495*d7f7bf2dSAxel Dörfler startY2 = ceilf(startY2); 496*d7f7bf2dSAxel Dörfler 497*d7f7bf2dSAxel Dörfler float endX1; 498*d7f7bf2dSAxel Dörfler float endY1; 499*d7f7bf2dSAxel Dörfler float endX2; 500*d7f7bf2dSAxel Dörfler float endY2; 501*d7f7bf2dSAxel Dörfler fTextDocumentLayout.GetTextBounds(end, endX1, endY1, endX2, endY2); 502*d7f7bf2dSAxel Dörfler 503*d7f7bf2dSAxel Dörfler endX1 = floorf(endX1); 504*d7f7bf2dSAxel Dörfler endY1 = floorf(endY1); 505*d7f7bf2dSAxel Dörfler endX2 = ceilf(endX2); 506*d7f7bf2dSAxel Dörfler endY2 = ceilf(endY2); 507*d7f7bf2dSAxel Dörfler 508*d7f7bf2dSAxel Dörfler int32 startLineIndex = fTextDocumentLayout.LineIndexForOffset(start); 509*d7f7bf2dSAxel Dörfler int32 endLineIndex = fTextDocumentLayout.LineIndexForOffset(end); 510*d7f7bf2dSAxel Dörfler 511*d7f7bf2dSAxel Dörfler if (startLineIndex == endLineIndex) { 512*d7f7bf2dSAxel Dörfler // Selection on one line 513*d7f7bf2dSAxel Dörfler BPoint lt(startX1, startY1); 514*d7f7bf2dSAxel Dörfler BPoint rt(endX1, endY1); 515*d7f7bf2dSAxel Dörfler BPoint rb(endX1, endY2); 516*d7f7bf2dSAxel Dörfler BPoint lb(startX1, startY2); 517*d7f7bf2dSAxel Dörfler 518*d7f7bf2dSAxel Dörfler shape.MoveTo(lt); 519*d7f7bf2dSAxel Dörfler shape.LineTo(rt); 520*d7f7bf2dSAxel Dörfler shape.LineTo(rb); 521*d7f7bf2dSAxel Dörfler shape.LineTo(lb); 522*d7f7bf2dSAxel Dörfler shape.Close(); 523*d7f7bf2dSAxel Dörfler } else if (startLineIndex == endLineIndex - 1 && endX1 <= startX1) { 524*d7f7bf2dSAxel Dörfler // Selection on two lines, with gap: 525*d7f7bf2dSAxel Dörfler // --------- 526*d7f7bf2dSAxel Dörfler // ------### 527*d7f7bf2dSAxel Dörfler // ##------- 528*d7f7bf2dSAxel Dörfler // --------- 529*d7f7bf2dSAxel Dörfler float width = ceilf(fTextDocumentLayout.Width()); 530*d7f7bf2dSAxel Dörfler 531*d7f7bf2dSAxel Dörfler BPoint lt(startX1, startY1); 532*d7f7bf2dSAxel Dörfler BPoint rt(width, startY1); 533*d7f7bf2dSAxel Dörfler BPoint rb(width, startY2); 534*d7f7bf2dSAxel Dörfler BPoint lb(startX1, startY2); 535*d7f7bf2dSAxel Dörfler 536*d7f7bf2dSAxel Dörfler shape.MoveTo(lt); 537*d7f7bf2dSAxel Dörfler shape.LineTo(rt); 538*d7f7bf2dSAxel Dörfler shape.LineTo(rb); 539*d7f7bf2dSAxel Dörfler shape.LineTo(lb); 540*d7f7bf2dSAxel Dörfler shape.Close(); 541*d7f7bf2dSAxel Dörfler 542*d7f7bf2dSAxel Dörfler lt = BPoint(0, endY1); 543*d7f7bf2dSAxel Dörfler rt = BPoint(endX1, endY1); 544*d7f7bf2dSAxel Dörfler rb = BPoint(endX1, endY2); 545*d7f7bf2dSAxel Dörfler lb = BPoint(0, endY2); 546*d7f7bf2dSAxel Dörfler 547*d7f7bf2dSAxel Dörfler shape.MoveTo(lt); 548*d7f7bf2dSAxel Dörfler shape.LineTo(rt); 549*d7f7bf2dSAxel Dörfler shape.LineTo(rb); 550*d7f7bf2dSAxel Dörfler shape.LineTo(lb); 551*d7f7bf2dSAxel Dörfler shape.Close(); 552*d7f7bf2dSAxel Dörfler } else { 553*d7f7bf2dSAxel Dörfler // Selection over multiple lines 554*d7f7bf2dSAxel Dörfler float width = ceilf(fTextDocumentLayout.Width()); 555*d7f7bf2dSAxel Dörfler 556*d7f7bf2dSAxel Dörfler shape.MoveTo(BPoint(startX1, startY1)); 557*d7f7bf2dSAxel Dörfler shape.LineTo(BPoint(width, startY1)); 558*d7f7bf2dSAxel Dörfler shape.LineTo(BPoint(width, endY1)); 559*d7f7bf2dSAxel Dörfler shape.LineTo(BPoint(endX1, endY1)); 560*d7f7bf2dSAxel Dörfler shape.LineTo(BPoint(endX1, endY2)); 561*d7f7bf2dSAxel Dörfler shape.LineTo(BPoint(0, endY2)); 562*d7f7bf2dSAxel Dörfler shape.LineTo(BPoint(0, startY2)); 563*d7f7bf2dSAxel Dörfler shape.LineTo(BPoint(startX1, startY2)); 564*d7f7bf2dSAxel Dörfler shape.Close(); 565*d7f7bf2dSAxel Dörfler } 566*d7f7bf2dSAxel Dörfler } 567*d7f7bf2dSAxel Dörfler 568*d7f7bf2dSAxel Dörfler 569