btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / webpositive / autocompletion / AutoCompleterDefaultImpl.cpp
blobf4cc594a283a0dfda7660df2b508280a61ec3d19
1 /*
2 * Copyright 2002-2006, project beam (http://sourceforge.net/projects/beam).
3 * All rights reserved. Distributed under the terms of the MIT License.
5 * Authors:
6 * Oliver Tappe <beam@hirschkaefer.de>
7 */
9 #include "AutoCompleterDefaultImpl.h"
11 #include <ListView.h>
12 #include <Screen.h>
13 #include <ScrollView.h>
14 #include <Window.h>
17 // #pragma mark - BDefaultPatternSelector
20 void
21 BDefaultPatternSelector::SelectPatternBounds(const BString& text,
22 int32 caretPos, int32* start, int32* length)
24 if (!start || !length)
25 return;
26 *start = 0;
27 *length = text.Length();
31 // #pragma mark - BDefaultCompletionStyle
34 BDefaultCompletionStyle::BDefaultCompletionStyle(
35 BAutoCompleter::EditView* editView,
36 BAutoCompleter::ChoiceModel* choiceModel,
37 BAutoCompleter::ChoiceView* choiceView,
38 BAutoCompleter::PatternSelector* patternSelector)
40 CompletionStyle(editView, choiceModel, choiceView, patternSelector),
41 fSelectedIndex(-1),
42 fPatternStartPos(0),
43 fPatternLength(0),
44 fIgnoreEditViewStateChanges(false)
49 BDefaultCompletionStyle::~BDefaultCompletionStyle()
54 bool
55 BDefaultCompletionStyle::Select(int32 index)
57 if (!fChoiceView || !fChoiceModel || index == fSelectedIndex
58 || index < -1 || index >= fChoiceModel->CountChoices()) {
59 return false;
62 fSelectedIndex = index;
63 fChoiceView->SelectChoiceAt(index);
64 return true;
68 bool
69 BDefaultCompletionStyle::SelectNext(bool wrap)
71 if (!fChoiceModel || fChoiceModel->CountChoices() == 0)
72 return false;
74 int32 newIndex = fSelectedIndex + 1;
75 if (newIndex >= fChoiceModel->CountChoices()) {
76 if (wrap)
77 newIndex = 0;
78 else
79 newIndex = fSelectedIndex;
81 return Select(newIndex);
85 bool
86 BDefaultCompletionStyle::SelectPrevious(bool wrap)
88 if (!fChoiceModel || fChoiceModel->CountChoices() == 0)
89 return false;
91 int32 newIndex = fSelectedIndex - 1;
92 if (newIndex < 0) {
93 if (wrap)
94 newIndex = fChoiceModel->CountChoices() - 1;
95 else
96 newIndex = 0;
98 return Select(newIndex);
102 bool
103 BDefaultCompletionStyle::IsChoiceSelected() const
105 return fSelectedIndex >= 0;
109 int32
110 BDefaultCompletionStyle::SelectedChoiceIndex() const
112 return fSelectedIndex;
116 void
117 BDefaultCompletionStyle::ApplyChoice(bool hideChoices)
119 if (!fChoiceModel || !fChoiceView || !fEditView || fSelectedIndex < 0)
120 return;
122 BString completedText(fFullEnteredText);
123 completedText.Remove(fPatternStartPos, fPatternLength);
124 const BString& choiceStr = fChoiceModel->ChoiceAt(fSelectedIndex)->Text();
125 completedText.Insert(choiceStr, fPatternStartPos);
127 fIgnoreEditViewStateChanges = true;
129 fFullEnteredText = completedText;
130 fPatternLength = choiceStr.Length();
131 fEditView->SetEditViewState(completedText,
132 fPatternStartPos + choiceStr.Length());
134 if (hideChoices) {
135 fChoiceView->HideChoices();
136 Select(-1);
139 fIgnoreEditViewStateChanges = false;
143 void
144 BDefaultCompletionStyle::CancelChoice()
146 if (!fChoiceView || !fEditView)
147 return;
148 if (fChoiceView->ChoicesAreShown()) {
149 fIgnoreEditViewStateChanges = true;
151 fEditView->SetEditViewState(fFullEnteredText,
152 fPatternStartPos + fPatternLength);
153 fChoiceView->HideChoices();
154 Select(-1);
156 fIgnoreEditViewStateChanges = false;
160 void
161 BDefaultCompletionStyle::EditViewStateChanged(bool updateChoices)
163 if (fIgnoreEditViewStateChanges || !fChoiceModel || !fChoiceView
164 || !fEditView) {
165 return;
168 BString text;
169 int32 caretPos;
170 fEditView->GetEditViewState(text, &caretPos);
171 if (fFullEnteredText == text)
172 return;
174 fFullEnteredText = text;
176 if (!updateChoices)
177 return;
179 fPatternSelector->SelectPatternBounds(text, caretPos, &fPatternStartPos,
180 &fPatternLength);
181 BString pattern(text.String() + fPatternStartPos, fPatternLength);
182 fChoiceModel->FetchChoicesFor(pattern);
184 Select(-1);
185 // show a single choice only if it doesn't match the pattern exactly:
186 if (fChoiceModel->CountChoices() > 1 || (fChoiceModel->CountChoices() == 1
187 && pattern.ICompare(fChoiceModel->ChoiceAt(0)->Text())) != 0) {
188 fChoiceView->ShowChoices(this);
189 fChoiceView->SelectChoiceAt(fSelectedIndex);
190 } else
191 fChoiceView->HideChoices();
195 // #pragma mark - BDefaultChoiceView::ListView
198 static const int32 MSG_INVOKED = 'invk';
201 BDefaultChoiceView::ListView::ListView(
202 BAutoCompleter::CompletionStyle* completer)
204 BListView(BRect(0, 0, 100, 100), "ChoiceViewList"),
205 fCompleter(completer)
207 // we need to check if user clicks outside of window-bounds:
208 SetEventMask(B_POINTER_EVENTS);
212 void
213 BDefaultChoiceView::ListView::AttachedToWindow()
215 SetTarget(this);
216 SetInvocationMessage(new BMessage(MSG_INVOKED));
217 BListView::AttachedToWindow();
221 void
222 BDefaultChoiceView::ListView::SelectionChanged()
224 fCompleter->Select(CurrentSelection(0));
228 void
229 BDefaultChoiceView::ListView::MessageReceived(BMessage* message)
231 switch(message->what) {
232 case MSG_INVOKED:
233 fCompleter->ApplyChoice();
234 break;
235 default:
236 BListView::MessageReceived(message);
241 void
242 BDefaultChoiceView::ListView::MouseDown(BPoint point)
244 if (!Window()->Frame().Contains(ConvertToScreen(point)))
245 // click outside of window, so we close it:
246 Window()->Quit();
247 else
248 BListView::MouseDown(point);
252 // #pragma mark - BDefaultChoiceView::ListItem
255 BDefaultChoiceView::ListItem::ListItem(const BAutoCompleter::Choice* choice)
257 BListItem()
259 fPreText = choice->DisplayText();
260 if (choice->MatchLen() > 0) {
261 fPreText.MoveInto(fMatchText, choice->MatchPos(), choice->MatchLen());
262 fPreText.MoveInto(fPostText, choice->MatchPos(), fPreText.Length());
267 void
268 BDefaultChoiceView::ListItem::DrawItem(BView* owner, BRect frame,
269 bool complete)
271 rgb_color textColor;
272 rgb_color nonMatchTextColor;
273 rgb_color backColor;
274 rgb_color matchColor;
275 if (IsSelected()) {
276 textColor = ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR);
277 backColor = ui_color(B_LIST_SELECTED_BACKGROUND_COLOR);
278 } else {
279 textColor = ui_color(B_LIST_ITEM_TEXT_COLOR);
280 backColor = ui_color(B_LIST_BACKGROUND_COLOR);
282 matchColor = tint_color(backColor, (B_NO_TINT + B_DARKEN_1_TINT) / 2);
283 if (textColor.red + textColor.green + textColor.blue > 128 * 3)
284 nonMatchTextColor = tint_color(textColor, 1.2);
285 else
286 nonMatchTextColor = tint_color(textColor, 0.75);
287 BFont font;
288 font_height fontHeight;
289 owner->GetFont(&font);
290 font.GetHeight(&fontHeight);
291 float xPos = frame.left + 1;
292 float yPos = frame.top + fontHeight.ascent;
293 float w;
294 if (fPreText.Length()) {
295 w = owner->StringWidth(fPreText.String());
296 owner->SetLowColor(backColor);
297 owner->FillRect(BRect(xPos, frame.top, xPos + w - 1, frame.bottom),
298 B_SOLID_LOW);
299 owner->SetHighColor(nonMatchTextColor);
300 owner->DrawString(fPreText.String(), BPoint(xPos, yPos));
301 xPos += w;
303 if (fMatchText.Length()) {
304 w = owner->StringWidth(fMatchText.String());
305 owner->SetLowColor(matchColor);
306 owner->FillRect(BRect(xPos, frame.top, xPos + w - 1, frame.bottom),
307 B_SOLID_LOW);
308 owner->SetHighColor(textColor);
309 owner->DrawString(fMatchText.String(), BPoint(xPos, yPos));
310 xPos += w;
312 if (fPostText.Length()) {
313 w = owner->StringWidth(fPostText.String());
314 owner->SetLowColor(backColor);
315 owner->FillRect(BRect(xPos, frame.top, xPos + w - 1, frame.bottom),
316 B_SOLID_LOW);
317 owner->SetHighColor(nonMatchTextColor);
318 owner->DrawString(fPostText.String(), BPoint(xPos, yPos));
323 // #pragma mark - BDefaultChoiceView
326 BDefaultChoiceView::BDefaultChoiceView()
328 fWindow(NULL),
329 fListView(NULL),
330 fMaxVisibleChoices(8)
336 BDefaultChoiceView::~BDefaultChoiceView()
338 HideChoices();
342 void
343 BDefaultChoiceView::SelectChoiceAt(int32 index)
345 if (fListView && fListView->LockLooper()) {
346 if (index < 0)
347 fListView->DeselectAll();
348 else {
349 fListView->Select(index);
350 fListView->ScrollToSelection();
352 fListView->UnlockLooper();
357 void
358 BDefaultChoiceView::ShowChoices(BAutoCompleter::CompletionStyle* completer)
360 if (!completer)
361 return;
363 HideChoices();
365 BAutoCompleter::ChoiceModel* choiceModel = completer->GetChoiceModel();
366 BAutoCompleter::EditView* editView = completer->GetEditView();
368 if (!editView || !choiceModel || choiceModel->CountChoices() == 0)
369 return;
371 fListView = new ListView(completer);
372 int32 count = choiceModel->CountChoices();
373 for(int32 i = 0; i<count; ++i) {
374 fListView->AddItem(
375 new ListItem(choiceModel->ChoiceAt(i))
379 BScrollView *scrollView = NULL;
380 if (count > fMaxVisibleChoices) {
381 scrollView = new BScrollView("", fListView, B_FOLLOW_NONE, 0, false, true, B_NO_BORDER);
384 fWindow = new BWindow(BRect(0, 0, 100, 100), "", B_BORDERED_WINDOW_LOOK,
385 B_NORMAL_WINDOW_FEEL, B_NOT_MOVABLE | B_WILL_ACCEPT_FIRST_CLICK
386 | B_AVOID_FOCUS | B_ASYNCHRONOUS_CONTROLS);
387 if (scrollView != NULL)
388 fWindow->AddChild(scrollView);
389 else
390 fWindow->AddChild(fListView);
392 int32 visibleCount = min_c(count, fMaxVisibleChoices);
393 float listHeight = fListView->ItemFrame(visibleCount - 1).bottom + 1;
395 BRect pvRect = editView->GetAdjustmentFrame();
396 BRect listRect = pvRect;
397 listRect.bottom = listRect.top + listHeight - 1;
398 BRect screenRect = BScreen().Frame();
399 if (listRect.bottom + 1 + listHeight <= screenRect.bottom)
400 listRect.OffsetTo(pvRect.left, pvRect.bottom + 1);
401 else
402 listRect.OffsetTo(pvRect.left, pvRect.top - listHeight);
404 if (scrollView != NULL) {
405 // Moving here to cut off the scrollbar top
406 scrollView->MoveTo(0, -1);
407 // Adding the 1 and 2 to cut-off the scroll-bar top, right and bottom
408 scrollView->ResizeTo(listRect.Width() + 1, listRect.Height() + 2);
409 // Move here to compensate for the above
410 fListView->MoveTo(0, 1);
411 fListView->ResizeTo(listRect.Width() - B_V_SCROLL_BAR_WIDTH, listRect.Height());
412 } else {
413 fListView->MoveTo(0, 0);
414 fListView->ResizeTo(listRect.Width(), listRect.Height());
416 fWindow->MoveTo(listRect.left, listRect.top);
417 fWindow->ResizeTo(listRect.Width(), listRect.Height());
418 fWindow->Show();
422 void
423 BDefaultChoiceView::HideChoices()
425 if (fWindow && fWindow->Lock()) {
426 fWindow->Quit();
427 fWindow = NULL;
428 fListView = NULL;
433 bool
434 BDefaultChoiceView::ChoicesAreShown()
436 return (fWindow != NULL);
440 int32
441 BDefaultChoiceView::CountVisibleChoices() const
443 if (fListView)
444 return min_c(fMaxVisibleChoices, fListView->CountItems());
445 else
446 return 0;
450 void
451 BDefaultChoiceView::SetMaxVisibleChoices(int32 choices)
453 if (choices < 1)
454 choices = 1;
455 if (choices == fMaxVisibleChoices)
456 return;
458 fMaxVisibleChoices = choices;
460 // TODO: Update live?
464 int32
465 BDefaultChoiceView::MaxVisibleChoices() const
467 return fMaxVisibleChoices;