xref: /haiku/src/apps/haikudepot/textview/TextDocumentView.cpp (revision d7f7bf2d890f652e20b8cf34e9b4c6ae1d3e20eb)
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