haiku/src/apps/stylededit/StatusView.cpp

305 lines
6.6 KiB
C++

/*
* Copyright 2002-2012, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Vlad Slepukhin
* Siarzhuk Zharski
*/
#include "StatusView.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Catalog.h>
#include <CharacterSet.h>
#include <CharacterSetRoster.h>
#include <ControlLook.h>
#include <MenuItem.h>
#include <Message.h>
#include <PopUpMenu.h>
#include <ScrollView.h>
#include <StringView.h>
#include <Window.h>
#include <tracker_private.h>
#include "DirMenu.h"
#include "Constants.h"
const float kHorzSpacing = 5.f;
#define UTF8_EXPAND_ARROW "\xe2\x96\xbe"
using namespace BPrivate;
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "StatusView"
StatusView::StatusView(BScrollView* scrollView)
:
BView(BRect(), "statusview",
B_FOLLOW_BOTTOM | B_FOLLOW_LEFT, B_WILL_DRAW),
fScrollView(scrollView),
fPreferredSize(0., 0.),
fReadOnly(false),
fCanUnlock(false)
{
memset(fCellWidth, 0, sizeof(fCellWidth));
}
StatusView::~StatusView()
{
}
void
StatusView::AttachedToWindow()
{
SetFont(be_plain_font);
SetFontSize(10. * be_plain_font->Size() / 12.f);
BMessage message(UPDATE_STATUS);
message.AddInt32("line", 1);
message.AddInt32("column", 1);
message.AddString("encoding", "");
SetStatus(&message);
BScrollBar* scrollBar = fScrollView->ScrollBar(B_HORIZONTAL);
MoveTo(0., scrollBar->Frame().top);
rgb_color color = B_TRANSPARENT_COLOR;
BView* parent = Parent();
if (parent != NULL)
color = parent->ViewColor();
if (color == B_TRANSPARENT_COLOR)
color = ui_color(B_PANEL_BACKGROUND_COLOR);
SetViewColor(color);
ResizeToPreferred();
}
void
StatusView::GetPreferredSize(float* _width, float* _height)
{
_ValidatePreferredSize();
if (_width)
*_width = fPreferredSize.width;
if (_height)
*_height = fPreferredSize.height;
}
void
StatusView::ResizeToPreferred()
{
float width, height;
GetPreferredSize(&width, &height);
if (Bounds().Width() > width)
width = Bounds().Width();
BView::ResizeTo(width, height);
}
void
StatusView::Draw(BRect updateRect)
{
if (fPreferredSize.width <= 0)
return;
if (be_control_look != NULL) {
BRect bounds(Bounds());
be_control_look->DrawMenuBarBackground(this,
bounds, updateRect, ViewColor());
}
BRect bounds(Bounds());
SetHighColor(tint_color(ViewColor(), B_DARKEN_2_TINT));
StrokeLine(bounds.LeftTop(), bounds.RightTop());
float x = bounds.left;
for (size_t i = 0; i < kStatusCellCount - 1; i++) {
x += fCellWidth[i];
StrokeLine(BPoint(x, bounds.top + 3), BPoint(x, bounds.bottom - 3));
}
SetLowColor(ViewColor());
SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
font_height fontHeight;
GetFontHeight(&fontHeight);
x = bounds.left;
float y = (bounds.bottom + bounds.top
+ ceilf(fontHeight.ascent) - ceilf(fontHeight.descent)) / 2;
for (size_t i = 0; i < kStatusCellCount; i++) {
if (fCellText[i].Length() == 0)
continue;
DrawString(fCellText[i], BPoint(x + kHorzSpacing, y));
x += fCellWidth[i];
}
}
void
StatusView::MouseDown(BPoint where)
{
if (where.x < fCellWidth[kPositionCell]) {
_ShowDirMenu();
return;
}
if (!fReadOnly || !fCanUnlock)
return;
float left = fCellWidth[kPositionCell] + fCellWidth[kEncodingCell];
if (where.x < left)
return;
int32 clicks = 0;
BMessage* message = Window()->CurrentMessage();
if (message != NULL
&& message->FindInt32("clicks", &clicks) == B_OK && clicks > 1)
return;
BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false);
menu->AddItem(new BMenuItem(B_TRANSLATE("Unlock file"),
new BMessage(UNLOCK_FILE)));
where.x = left;
where.y = Bounds().bottom;
ConvertToScreen(&where);
menu->SetTargetForItems(this);
menu->Go(where, true, true, true);
}
void
StatusView::SetStatus(BMessage* message)
{
int32 line = 0, column = 0;
if (B_OK == message->FindInt32("line", &line)
&& B_OK == message->FindInt32("column", &column))
{
char info[256];
snprintf(info, sizeof(info),
B_TRANSLATE("line %d, column %d"), line, column);
fCellText[kPositionCell].SetTo(info);
}
if (B_OK == message->FindString("encoding", &fEncoding)) {
// sometime corresponding Int-32 "encoding" attrib is read as string :(
if (fEncoding.Length() == 0
|| fEncoding.Compare("\xff\xff") == 0
|| fEncoding.Compare("UTF-8") == 0)
{
// do not display default UTF-8 encoding
fCellText[kEncodingCell].Truncate(0);
fEncoding.Truncate(0);
} else {
const BCharacterSet* charset
= BCharacterSetRoster::FindCharacterSetByName(fEncoding);
fCellText[kEncodingCell]
= charset != NULL ? charset->GetPrintName() : "";
}
}
bool modified = false;
fReadOnly = false;
fCanUnlock = false;
if (B_OK == message->FindBool("modified", &modified) && modified) {
fCellText[kFileStateCell] = B_TRANSLATE("Modified");
} else if (B_OK == message->FindBool("readOnly", &fReadOnly) && fReadOnly) {
fCellText[kFileStateCell] = B_TRANSLATE("Read-only");
if (B_OK == message->FindBool("canUnlock", &fCanUnlock) && fCanUnlock)
fCellText[kFileStateCell] << " " UTF8_EXPAND_ARROW;
} else
fCellText[kFileStateCell].Truncate(0);
_ValidatePreferredSize();
Invalidate();
}
void
StatusView::SetRef(const entry_ref& ref)
{
fRef = ref;
}
void
StatusView::_ValidatePreferredSize()
{
float orgWidth = fPreferredSize.width;
// width
fPreferredSize.width = 0.f;
for (size_t i = 0; i < kStatusCellCount; i++) {
if (fCellText[i].Length() == 0) {
fCellWidth[i] = 0;
continue;
}
float width = ceilf(StringWidth(fCellText[i]));
if (width > 0)
width += kHorzSpacing * 2;
if (width > fCellWidth[i] || i != kPositionCell)
fCellWidth[i] = width;
fPreferredSize.width += fCellWidth[i];
}
// height
font_height fontHeight;
GetFontHeight(&fontHeight);
fPreferredSize.height = ceilf(fontHeight.ascent + fontHeight.descent
+ fontHeight.leading);
if (fPreferredSize.height < B_H_SCROLL_BAR_HEIGHT)
fPreferredSize.height = B_H_SCROLL_BAR_HEIGHT;
float delta = fPreferredSize.width - orgWidth;
ResizeBy(delta, 0);
BScrollBar* scrollBar = fScrollView->ScrollBar(B_HORIZONTAL);
scrollBar->ResizeBy(-delta, 0);
scrollBar->MoveBy(delta, 0);
}
void
StatusView::_ShowDirMenu()
{
BEntry entry;
status_t status = entry.SetTo(&fRef);
if (status != B_OK || !entry.Exists())
return;
BPrivate::BDirMenu* menu = new BDirMenu(NULL,
BMessenger(kTrackerSignature), B_REFS_RECEIVED);
menu->Populate(&entry, Window(), false, false, true, false, true);
BPoint point = Bounds().LeftBottom();
point.y += 3;
ConvertToScreen(&point);
BRect clickToOpenRect(Bounds());
ConvertToScreen(&clickToOpenRect);
menu->Go(point, true, true, clickToOpenRect);
delete menu;
}