1 /* 2 * Copyright 2002-2012, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Vlad Slepukhin 7 * Siarzhuk Zharski 8 */ 9 10 11 #include "StatusView.h" 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 #include <Catalog.h> 18 #include <CharacterSet.h> 19 #include <CharacterSetRoster.h> 20 #include <ControlLook.h> 21 #include <MenuItem.h> 22 #include <Message.h> 23 #include <PopUpMenu.h> 24 #include <ScrollView.h> 25 #include <StringView.h> 26 #include <Window.h> 27 28 #include "Constants.h" 29 #include "StyledEditWindow.h" 30 31 32 const float kHorzSpacing = 5.f; 33 #define UTF8_EXPAND_ARROW "\xe2\x96\xbe" 34 35 using namespace BPrivate; 36 37 38 #undef B_TRANSLATION_CONTEXT 39 #define B_TRANSLATION_CONTEXT "StatusView" 40 41 42 StatusView::StatusView(BScrollView* scrollView) 43 : 44 BView(BRect(), "statusview", 45 B_FOLLOW_BOTTOM | B_FOLLOW_LEFT, B_WILL_DRAW), 46 fScrollView(scrollView), 47 fPreferredSize(0., 0.), 48 fReadOnly(false) 49 { 50 memset(fCellWidth, 0, sizeof(fCellWidth)); 51 } 52 53 54 StatusView::~StatusView() 55 { 56 } 57 58 59 void 60 StatusView::AttachedToWindow() 61 { 62 SetFont(be_plain_font); 63 SetFontSize(10.); 64 65 BMessage message(UPDATE_STATUS); 66 message.AddInt32("line", 1); 67 message.AddInt32("column", 1); 68 message.AddString("encoding", ""); 69 SetStatus(&message); 70 71 BScrollBar* scrollBar = fScrollView->ScrollBar(B_HORIZONTAL); 72 MoveTo(0., scrollBar->Frame().top); 73 74 rgb_color color = B_TRANSPARENT_COLOR; 75 BView* parent = Parent(); 76 if (parent != NULL) 77 color = parent->ViewColor(); 78 79 if (color == B_TRANSPARENT_COLOR) 80 color = ui_color(B_PANEL_BACKGROUND_COLOR); 81 82 SetViewColor(color); 83 84 ResizeToPreferred(); 85 } 86 87 88 void 89 StatusView::GetPreferredSize(float* _width, float* _height) 90 { 91 _ValidatePreferredSize(); 92 93 if (_width) 94 *_width = fPreferredSize.width; 95 96 if (_height) 97 *_height = fPreferredSize.height; 98 } 99 100 101 void 102 StatusView::ResizeToPreferred() 103 { 104 float width, height; 105 GetPreferredSize(&width, &height); 106 107 if (Bounds().Width() > width) 108 width = Bounds().Width(); 109 110 BView::ResizeTo(width, height); 111 } 112 113 114 void 115 StatusView::Draw(BRect updateRect) 116 { 117 if (fPreferredSize.width <= 0) 118 return; 119 120 if (be_control_look != NULL) { 121 BRect bounds(Bounds()); 122 be_control_look->DrawMenuBarBackground(this, 123 bounds, updateRect, ViewColor()); 124 } 125 126 BRect bounds(Bounds()); 127 rgb_color highColor = HighColor(); 128 SetHighColor(tint_color(ViewColor(), B_DARKEN_2_TINT)); 129 StrokeLine(bounds.LeftTop(), bounds.RightTop()); 130 131 float x = bounds.left; 132 for (size_t i = 0; i < kStatusCellCount - 1; i++) { 133 x += fCellWidth[i]; 134 StrokeLine(BPoint(x, bounds.top + 3), BPoint(x, bounds.bottom - 3)); 135 } 136 137 SetLowColor(ViewColor()); 138 SetHighColor(highColor); 139 140 font_height fontHeight; 141 GetFontHeight(&fontHeight); 142 143 x = bounds.left; 144 float y = (bounds.bottom + bounds.top 145 + ceilf(fontHeight.ascent) - ceilf(fontHeight.descent)) / 2; 146 147 for (size_t i = 0; i < kStatusCellCount; i++) { 148 if (fCellText[i].Length() == 0) 149 continue; 150 DrawString(fCellText[i], BPoint(x + kHorzSpacing, y)); 151 x += fCellWidth[i]; 152 } 153 } 154 155 156 void 157 StatusView::MouseDown(BPoint where) 158 { 159 if (!fReadOnly) 160 return; 161 162 if (where.x < fCellWidth[kPositionCell]) 163 return; 164 165 int32 clicks = 0; 166 BMessage* message = Window()->CurrentMessage(); 167 if (message != NULL 168 && message->FindInt32("clicks", &clicks) == B_OK && clicks > 1) 169 return; 170 171 BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false); 172 float left = fCellWidth[kPositionCell] + fCellWidth[kEncodingCell]; 173 if (where.x < left) 174 StyledEditWindow::PopulateEncodingMenu(menu, fEncoding); 175 else 176 menu->AddItem(new BMenuItem(B_TRANSLATE("Unlock file"), 177 new BMessage(UNLOCK_FILE))); 178 where.x = left; 179 where.y = Bounds().bottom; 180 181 ConvertToScreen(&where); 182 menu->SetTargetForItems(this); 183 menu->Go(where, true, true, true); 184 } 185 186 187 void 188 StatusView::SetStatus(BMessage* message) 189 { 190 int32 line = 0, column = 0; 191 if (B_OK == message->FindInt32("line", &line) 192 && B_OK == message->FindInt32("column", &column)) 193 { 194 char info[256]; 195 snprintf(info, sizeof(info), 196 B_TRANSLATE("line %d, column %d"), line, column); 197 fCellText[kPositionCell].SetTo(info); 198 } 199 200 if (B_OK == message->FindString("encoding", &fEncoding)) { 201 // sometime corresponding Int-32 "encoding" attrib is read as string :( 202 if (fEncoding.Length() == 0 203 || fEncoding.Compare("\xff\xff") == 0 204 || fEncoding.Compare("UTF-8") == 0) 205 { 206 fCellText[kEncodingCell] = "UTF-8"; 207 fEncoding.Truncate(0); 208 } else { 209 const BCharacterSet* charset 210 = BCharacterSetRoster::FindCharacterSetByName(fEncoding); 211 fCellText[kEncodingCell] 212 = charset != NULL ? charset->GetPrintName() : ""; 213 } 214 fCellText[kEncodingCell] << " " UTF8_EXPAND_ARROW; 215 } 216 217 bool modified = false; 218 fReadOnly = false; 219 if (B_OK == message->FindBool("modified", &modified) && modified) { 220 fCellText[kFileStateCell] = B_TRANSLATE("Modified"); 221 } else if (B_OK == message->FindBool("readOnly", &fReadOnly) && fReadOnly) { 222 fCellText[kFileStateCell] = B_TRANSLATE("Read-only"); 223 fCellText[kFileStateCell] << " " UTF8_EXPAND_ARROW; 224 } else 225 fCellText[kFileStateCell].Truncate(0); 226 227 _ValidatePreferredSize(); 228 Invalidate(); 229 } 230 231 232 void 233 StatusView::_ValidatePreferredSize() 234 { 235 float orgWidth = fPreferredSize.width; 236 // width 237 fPreferredSize.width = 0.f; 238 for (size_t i = 0; i < kStatusCellCount; i++) { 239 if (fCellText[i].Length() == 0) { 240 fCellWidth[i] = 0; 241 continue; 242 } 243 float width = ceilf(StringWidth(fCellText[i])); 244 if (width > 0) 245 width += kHorzSpacing * 2; 246 if (width > fCellWidth[i] || i != kPositionCell) 247 fCellWidth[i] = width; 248 fPreferredSize.width += fCellWidth[i]; 249 } 250 251 // height 252 font_height fontHeight; 253 GetFontHeight(&fontHeight); 254 255 fPreferredSize.height = ceilf(fontHeight.ascent + fontHeight.descent 256 + fontHeight.leading); 257 258 if (fPreferredSize.height < B_H_SCROLL_BAR_HEIGHT) 259 fPreferredSize.height = B_H_SCROLL_BAR_HEIGHT; 260 261 float delta = fPreferredSize.width - orgWidth; 262 ResizeBy(delta, 0); 263 BScrollBar* scrollBar = fScrollView->ScrollBar(B_HORIZONTAL); 264 scrollBar->ResizeBy(-delta, 0); 265 scrollBar->MoveBy(delta, 0); 266 } 267 268