diff --git a/src/apps/Jamfile b/src/apps/Jamfile index 66b7364ecd..8b8b01e0f2 100644 --- a/src/apps/Jamfile +++ b/src/apps/Jamfile @@ -7,6 +7,7 @@ SubInclude HAIKU_TOP src apps autoraise ; SubInclude HAIKU_TOP src apps bsnow ; SubInclude HAIKU_TOP src apps bootman ; SubInclude HAIKU_TOP src apps cdplayer ; +SubInclude HAIKU_TOP src apps charactermap ; SubInclude HAIKU_TOP src apps clock ; SubInclude HAIKU_TOP src apps codycam ; SubInclude HAIKU_TOP src apps cortex ; diff --git a/src/apps/charactermap/CharacterMap.cpp b/src/apps/charactermap/CharacterMap.cpp new file mode 100644 index 0000000000..bdc6260fde --- /dev/null +++ b/src/apps/charactermap/CharacterMap.cpp @@ -0,0 +1,84 @@ +/* + * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "CharacterMap.h" + +#include + +#include +#include +#include + +#include "CharacterWindow.h" + + +const char* kSignature = "application/x-vnd.Haiku-CharacterMap"; + + +CharacterMap::CharacterMap() + : BApplication(kSignature) +{ +} + + +CharacterMap::~CharacterMap() +{ +} + + +void +CharacterMap::ReadyToRun() +{ + fWindow = new CharacterWindow(); + fWindow->Show(); +} + + +void +CharacterMap::RefsReceived(BMessage* message) +{ + fWindow->PostMessage(message); +} + + +void +CharacterMap::MessageReceived(BMessage* message) +{ + BApplication::MessageReceived(message); +} + + +void +CharacterMap::AboutRequested() +{ + BAlert *alert = new BAlert("about", "CharacterMap\n" + "\twritten by Axel Dörfler\n" + "\tCopyright 2009, Haiku Inc.\n", "Ok"); + BTextView *view = alert->TextView(); + BFont font; + + view->SetStylable(true); + + view->GetFont(&font); + font.SetSize(18); + font.SetFace(B_BOLD_FACE); + view->SetFontAndColor(0, 12, &font); + + alert->Go(); +} + + +// #pragma mark - + + +int +main(int /*argc*/, char** /*argv*/) +{ + CharacterMap app; + app.Run(); + + return 0; +} diff --git a/src/apps/charactermap/CharacterMap.h b/src/apps/charactermap/CharacterMap.h new file mode 100644 index 0000000000..29c1e15dbb --- /dev/null +++ b/src/apps/charactermap/CharacterMap.h @@ -0,0 +1,33 @@ +/* + * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef CHARACTER_MAP_H +#define CHARACTER_MAP_H + + +#include + +class BMessage; +class CharacterWindow; + + +class CharacterMap : public BApplication { +public: + CharacterMap(); + virtual ~CharacterMap(); + + virtual void ReadyToRun(); + + virtual void RefsReceived(BMessage* message); + virtual void MessageReceived(BMessage* message); + + virtual void AboutRequested(); + +private: + CharacterWindow* fWindow; +}; + +extern const char* kSignature; + +#endif // CHARACTER_MAP_H diff --git a/src/apps/charactermap/CharacterMap.rdef b/src/apps/charactermap/CharacterMap.rdef new file mode 100644 index 0000000000..b45b93701d --- /dev/null +++ b/src/apps/charactermap/CharacterMap.rdef @@ -0,0 +1,32 @@ + +resource(1, "BEOS:APP_SIG") #'MIMS' "application/x-vnd.Haiku-CharacterMap"; + +resource app_version { + major = 1, + middle = 0, + minor = 0, + + variety = B_APPV_BETA, + internal = 0, + + short_info = "CharacterMap", + long_info = "CharacterMap ©2009 Haiku, Inc." +}; + +resource app_flags B_MULTIPLE_LAUNCH; + +resource vector_icon { + $"6E63696608050004005F020006023D5F39368F62B905F93FFB6B4ACB36BEDE32" + $"00032288FF1944E7020006023AAFCC3BFAA8BF50A93E3D044B460F48AEEC0002" + $"0258FF1919E7020006023BA7EB3CD6E4BF5D013E2A4C4B0DDA478DDF0097C3FF" + $"FF376AFF02000602380D3A384399BEF6CA3EAF9C4B2833C6F2DC00E3ECFFFFAC" + $"C7FF02000602371F7FB98A813FA8F13D3A58C4B8AC48909300CEDEFFFF3778FF" + $"02000602371F7FB98A813FA8F13D3A58C60C5648909300BADAFFFF032E850B0A" + $"0432482C503E543C4B0A0550485452485E565A60500A0A47273D24322A244A2C" + $"4E34C2B0BE5BC408BFBFC94F485C52520A0447273C2D485C52520A08BE5AC40E" + $"4058485CBE3D2D322A244A2C4EB935C20F0A03BC12BB843BC1D3B9EBC0700A03" + $"BC12BB84BCC2BE1AB9EBC0700A03BD75C0B13BC1D3B9EBC0700A03BCC2BE1ABD" + $"75C0B1B9EBC0700A032C4E34C2B0B939C20A0A043D24322A3C2D4727090A0102" + $"0001000A0001021001178400040A020103000A030109000A030106000A060107" + $"000A070108000A04020405000A05010A00" +}; diff --git a/src/apps/charactermap/CharacterView.cpp b/src/apps/charactermap/CharacterView.cpp new file mode 100644 index 0000000000..3f80c65b78 --- /dev/null +++ b/src/apps/charactermap/CharacterView.cpp @@ -0,0 +1,313 @@ +/* + * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "CharacterView.h" + +#include + +#include +#include + +#include "UnicodeBlocks.h" + + +void +unicode_to_utf8(uint32 c, char** out) +{ + char* s = *out; + + if (c < 0x80) + *(s++) = c; + else if (c < 0x800) { + *(s++) = 0xc0 | (c >> 6); + *(s++) = 0x80 | (c & 0x3f); + } else if (c < 0x10000) { + *(s++) = 0xe0 | (c >> 12); + *(s++) = 0x80 | ((c >> 6) & 0x3f); + *(s++) = 0x80 | (c & 0x3f); + } else if (c <= 0x10ffff) { + *(s++) = 0xf0 | (c >> 18); + *(s++) = 0x80 | ((c >> 12) & 0x3f); + *(s++) = 0x80 | ((c >> 6) & 0x3f); + *(s++) = 0x80 | (c & 0x3f); + } + *out = s; +} + + +// #pragma mark - + + +CharacterView::CharacterView(const char* name) + : BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS), + fShowPrivateBlocks(false), + fShowContainedBlocksOnly(false) +{ + fTitleTops = new int32[kNumUnicodeBlocks]; + fCharacterFont.SetSize(fCharacterFont.Size() * 1.5f); +} + + +CharacterView::~CharacterView() +{ + delete[] fTitleTops; +} + + +void +CharacterView::SetCharacterFont(const BFont& font) +{ + fCharacterFont = font; + + InvalidateLayout(); +} + + +void +CharacterView::ShowPrivateBlocks(bool show) +{ + if (fShowPrivateBlocks == show) + return; + + fShowPrivateBlocks = show; + InvalidateLayout(); +} + + +void +CharacterView::ShowContainedBlocksOnly(bool show) +{ + if (fShowContainedBlocksOnly == show) + return; + + fShowContainedBlocksOnly = show; + InvalidateLayout(); +} + + +bool +CharacterView::IsShowingBlock(int32 blockIndex) const +{ + if (!fShowPrivateBlocks && kUnicodeBlocks[blockIndex].private_block) + return false; + + if (fShowContainedBlocksOnly + && !fCharacterFont.Blocks().Includes( + kUnicodeBlocks[blockIndex].block)) { + return false; + } + + return true; +} + + +void +CharacterView::ScrollTo(int32 blockIndex) +{ + if (blockIndex < 0) + blockIndex = 0; + else if (blockIndex >= (int32)kNumUnicodeBlocks) + blockIndex = kNumUnicodeBlocks - 1; + + BView::ScrollTo(0.0f, fTitleTops[blockIndex]); +} + + +void +CharacterView::AttachedToWindow() +{ +} + + +void +CharacterView::DetachedFromWindow() +{ +} + + +BSize +CharacterView::MinSize() +{ + return BLayoutUtils::ComposeSize(ExplicitMinSize(), + BSize(fCharacterHeight, fCharacterHeight + fTitleHeight)); +} + + +void +CharacterView::FrameResized(float width, float height) +{ + puts("hey"); + _UpdateSize(); +} + + +void +CharacterView::MouseDown(BPoint where) +{ +} + + +void +CharacterView::MouseUp(BPoint where) +{ +} + + +void +CharacterView::MouseMoved(BPoint where, uint32 transit, + const BMessage* dragMessage) +{ +} + + +void +CharacterView::MessageReceived(BMessage* message) +{ +} + + +void +CharacterView::Draw(BRect updateRect) +{ + const int32 kStartX = fGap / 2; + + BFont font; + GetFont(&font); + int32 y = 2; + + // TODO: jump to the correct start + for (uint32 i = 0; i < kNumUnicodeBlocks; i++) { + if (!IsShowingBlock(i)) + continue; + if (fTitleTops[i] > updateRect.bottom) + break; + + SetHighColor(0, 0, 0); + DrawString(kUnicodeBlocks[i].name, BPoint(3, y + fTitleBase)); + + y += fTitleHeight; + int32 x = kStartX; + SetFont(&fCharacterFont); + + char character[16]; + for (uint32 c = kUnicodeBlocks[i].start; c <= kUnicodeBlocks[i].end; + c++) { + if (y + fCharacterHeight > updateRect.top + && y < updateRect.bottom) { +#if 0 + // Stroke frame around the charater + SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); + StrokeRect(BRect(x, y, x + fCharacterWidth, + y + fCharacterHeight - fGap)); + + SetHighColor(0, 0, 0); +#endif + + // Draw character + char* end = character; + unicode_to_utf8(c, &end); + end[0] = '\0'; + + DrawString(character, + BPoint(x + (fCharacterWidth - StringWidth(character)) / 2, + y + fCharacterBase)); + } + + x += fCharacterWidth + fGap; + if (x + fCharacterWidth + fGap / 2 >= fDataRect.right) { + y += fCharacterHeight; + x = kStartX; + } + } + + if (x != kStartX) + y += fCharacterHeight; + y += fTitleGap; + + SetFont(&font); + } +} + + +void +CharacterView::DoLayout() +{ + _UpdateSize(); +} + + +void +CharacterView::_UpdateSize() +{ + // Compute data rect + + BRect bounds = Bounds(); + + font_height fontHeight; + GetFontHeight(&fontHeight); + fTitleHeight = (int32)ceilf(fontHeight.ascent + fontHeight.descent + + fontHeight.leading); + fTitleBase = (int32)ceilf(fontHeight.ascent); + + // Find widest character + fCharacterWidth = (int32)ceilf(fCharacterFont.StringWidth("W")); + + if (fCharacterFont.IsFullAndHalfFixed()) { + // TODO: improve this! + fCharacterWidth *= 2; + } + + fCharacterFont.GetHeight(&fontHeight); + fCharacterHeight = (int32)ceilf(fontHeight.ascent + fontHeight.descent + + fontHeight.leading); + fCharacterBase = (int32)ceilf(fontHeight.ascent); + + fGap = (int32)roundf(fCharacterHeight / 8.0); + if (fGap < 3) + fGap = 3; + + fCharacterHeight += fGap; + fTitleGap = fGap * 3; + + fDataRect.right = bounds.Width(); + fDataRect.bottom = 0; + + int32 charactersPerLine = int32(bounds.Width() / (fGap + fCharacterWidth)); + if (charactersPerLine == 0) + charactersPerLine = 1; + + for (uint32 i = 0; i < kNumUnicodeBlocks; i++) { + fTitleTops[i] = (int32)ceilf(fDataRect.bottom); + + if (!IsShowingBlock(i)) + continue; + + int32 lines = (kUnicodeBlocks[i].Count() + charactersPerLine - 1) + / charactersPerLine; + fDataRect.bottom += lines * fCharacterHeight + fTitleHeight + fTitleGap; + } + + // Update scroll bars + + BScrollBar* scroller = ScrollBar(B_VERTICAL); + if (scroller == NULL) + return; + + if (bounds.Height() > fDataRect.Height()) { + // no scrolling + scroller->SetRange(0.0f, 0.0f); + scroller->SetValue(0.0f); + } else { + scroller->SetRange(0.0f, fDataRect.Height() - bounds.Height() - 1.0f); + scroller->SetProportion(bounds.Height () / fDataRect.Height()); + // scroll up if there is empty room on bottom + if (fDataRect.Height() < bounds.bottom) { + ScrollBy(0.0f, bounds.bottom - fDataRect.Height()); + } + } + + Invalidate(); +} diff --git a/src/apps/charactermap/CharacterView.h b/src/apps/charactermap/CharacterView.h new file mode 100644 index 0000000000..487b0e7e65 --- /dev/null +++ b/src/apps/charactermap/CharacterView.h @@ -0,0 +1,70 @@ +/* + * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef CHARACTER_VIEW_H +#define CHARACTER_VIEW_H + + +#include + + +class CharacterView : public BView { +public: + CharacterView(const char* name); + virtual ~CharacterView(); + + void SetCharacterFont(const BFont& font); + const BFont& CharacterFont() { return fCharacterFont; } + + void ShowPrivateBlocks(bool show); + bool IsShowingPrivateBlocks() const + { return fShowPrivateBlocks; } + + void ShowContainedBlocksOnly(bool show); + bool IsShowingContainedBlocksOnly() const + { return fShowContainedBlocksOnly; } + + bool IsShowingBlock(int32 blockIndex) const; + + void ScrollTo(int32 blockIndex); + +protected: + virtual void AttachedToWindow(); + virtual void DetachedFromWindow(); + + virtual BSize MinSize(); + + virtual void FrameResized(float width, float height); + virtual void MouseDown(BPoint where); + virtual void MouseUp(BPoint where); + virtual void MouseMoved(BPoint where, uint32 transit, + const BMessage* dragMessage); + + virtual void MessageReceived(BMessage* message); + + virtual void Draw(BRect updateRect); + + virtual void DoLayout(); + +private: + bool _IncludeBlock(int32 index); + void _UpdateSize(); + +private: + bool fShowPrivateBlocks; + bool fShowContainedBlocksOnly; + + BRect fDataRect; + BFont fCharacterFont; + int32 fCharacterWidth; + int32 fCharacterHeight; + int32 fCharacterBase; + int32 fTitleHeight; + int32 fTitleBase; + int32 fGap; + int32 fTitleGap; + int32* fTitleTops; +}; + +#endif // CHARACTER_VIEW_H diff --git a/src/apps/charactermap/CharacterWindow.cpp b/src/apps/charactermap/CharacterWindow.cpp new file mode 100644 index 0000000000..330763ed13 --- /dev/null +++ b/src/apps/charactermap/CharacterWindow.cpp @@ -0,0 +1,412 @@ +/* + * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include "CharacterWindow.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CharacterView.h" +#include "UnicodeBlocks.h" + + +static const uint32 kMsgUnicodeBlockSelected = 'unbs'; +static const uint32 kMsgFontSelected = 'fnts'; +static const uint32 kMsgFontSizeChanged = 'fsch'; +static const uint32 kMsgPrivateBlocks = 'prbl'; +static const uint32 kMsgContainedBlocks = 'cnbl'; + +static const int32 kMinFontSize = 10; +static const int32 kMaxFontSize = 72; + + +class FontSizeSlider : public BSlider { +public: + FontSizeSlider(const char* name, const char* label, BMessage* message, + int32 min, int32 max) + : BSlider(name, label, NULL, min, max, B_HORIZONTAL) + { + SetModificationMessage(message); + } + +protected: + const char* UpdateText() const + { + snprintf(fText, sizeof(fText), "%ldpt", Value()); + return fText; + } + +private: + mutable char fText[32]; +}; + + +CharacterWindow::CharacterWindow() + : BWindow(BRect(100, 100, 500, 350), "CharacterMap", B_TITLED_WINDOW, + B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE | B_AUTO_UPDATE_SIZE_LIMITS) +{ + BMessage settings; + _LoadSettings(settings); + + BRect frame; + if (settings.FindRect("window frame", &frame) == B_OK) { + MoveTo(frame.LeftTop()); + ResizeTo(frame.Width(), frame.Height()); + } + + // create GUI + + SetLayout(new BGroupLayout(B_VERTICAL)); + + BMenuBar* menuBar = new BMenuBar("menu"); + + fUnicodeBlockView = new BListView("unicodeBlocks"); + fUnicodeBlockView->SetSelectionMessage( + new BMessage(kMsgUnicodeBlockSelected)); + + BScrollView* unicodeScroller = new BScrollView("unicodeScroller", + fUnicodeBlockView, 0, false, true); + + fCharacterView = new CharacterView("characters"); + + bool show; + if (settings.FindBool("show private blocks", &show) == B_OK) + fCharacterView->ShowPrivateBlocks(show); + if (settings.FindBool("show contained blocks only", &show) == B_OK) + fCharacterView->ShowContainedBlocksOnly(show); + + const char* family; + const char* style; + if (settings.FindString("font family", &family) == B_OK + && settings.FindString("font style", &style) == B_OK) { + _SetFont(family, style); + } + + int32 fontSize; + if (settings.FindInt32("font size", &fontSize) == B_OK) { + BFont font = fCharacterView->CharacterFont(); + if (fontSize < kMinFontSize) + fontSize = kMinFontSize; + else if (fontSize > kMaxFontSize) + fontSize = kMaxFontSize; + font.SetSize(fontSize); + + fCharacterView->SetCharacterFont(font); + } else + fontSize = (int32)fCharacterView->CharacterFont().Size(); + + BScrollView* characterScroller = new BScrollView("characterScroller", + fCharacterView, 0, false, true); + + fFontSizeSlider = new FontSizeSlider("fontSizeSlider", "Font Size:", + new BMessage(kMsgFontSizeChanged), kMinFontSize, kMaxFontSize); + fFontSizeSlider->SetValue(fontSize); + + AddChild(BGroupLayoutBuilder(B_VERTICAL) + .Add(menuBar) + .Add(BGroupLayoutBuilder()//BSplitLayoutBuilder() + .Add(unicodeScroller) + .Add(BGroupLayoutBuilder(B_VERTICAL) + .Add(characterScroller) + .Add(fFontSizeSlider)))); + + // Add menu + + // "File" menu + BMenu* menu = new BMenu("File"); + BMenuItem* item; + + menu->AddItem(item = new BMenuItem("About CharacterMap" B_UTF8_ELLIPSIS, + new BMessage(B_ABOUT_REQUESTED))); + + menu->AddSeparatorItem(); + + menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q')); + menu->SetTargetForItems(this); + item->SetTarget(be_app); + menuBar->AddItem(menu); + + menu = new BMenu("View"); + menu->AddItem(item = new BMenuItem("Show Private Blocks", + new BMessage(kMsgPrivateBlocks))); + item->SetMarked(fCharacterView->IsShowingPrivateBlocks()); + menu->AddItem(item = new BMenuItem("Only Show Blocks Contained in Font", + new BMessage(kMsgContainedBlocks))); + item->SetMarked(fCharacterView->IsShowingContainedBlocksOnly()); + menuBar->AddItem(menu); + + menuBar->AddItem(_CreateFontMenu()); + + _CreateUnicodeBlocks(); + InvalidateLayout(); +} + + +CharacterWindow::~CharacterWindow() +{ +} + + +void +CharacterWindow::MessageReceived(BMessage* message) +{ + switch (message->what) { + case kMsgUnicodeBlockSelected: + { + int32 index; + if (message->FindInt32("index", &index) != B_OK + || index < 0) + break; + + fCharacterView->ScrollTo(index); + break; + } + + case kMsgFontSelected: + { + BMenuItem* item; + if (message->FindPointer("source", (void**)&item) != B_OK) + break; + + fSelectedFontItem->SetMarked(false); + + if (item != NULL) { + item->SetMarked(true); + fSelectedFontItem = item; + + _SetFont(item->Menu()->Name(), item->Label()); + } + break; + } + + case kMsgFontSizeChanged: + { + int32 size = fFontSizeSlider->Value(); + if (size < kMinFontSize) + size = kMinFontSize; + else if (size > kMaxFontSize) + size = kMaxFontSize; + + BFont font = fCharacterView->CharacterFont(); + font.SetSize(size); + fCharacterView->SetCharacterFont(font); + break; + } + + case kMsgPrivateBlocks: + { + BMenuItem* item; + if (message->FindPointer("source", (void**)&item) != B_OK + || item == NULL) + break; + + item->SetMarked(!item->IsMarked()); + + fCharacterView->ShowPrivateBlocks(item->IsMarked()); + _UpdateUnicodeBlocks(); + break; + } + + case kMsgContainedBlocks: + { + BMenuItem* item; + if (message->FindPointer("source", (void**)&item) != B_OK + || item == NULL) + break; + + item->SetMarked(!item->IsMarked()); + + fCharacterView->ShowContainedBlocksOnly(item->IsMarked()); + _UpdateUnicodeBlocks(); + break; + } + + default: + BWindow::MessageReceived(message); + break; + } +} + + +bool +CharacterWindow::QuitRequested() +{ + _SaveSettings(); + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} + + +status_t +CharacterWindow::_OpenSettings(BFile& file, uint32 mode) +{ + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) + return B_ERROR; + + path.Append("CharacterMap settings"); + + return file.SetTo(path.Path(), mode); +} + + +status_t +CharacterWindow::_LoadSettings(BMessage& settings) +{ + BFile file; + status_t status = _OpenSettings(file, B_READ_ONLY); + if (status < B_OK) + return status; + + return settings.Unflatten(&file); +} + + +status_t +CharacterWindow::_SaveSettings() +{ + BFile file; + status_t status = _OpenSettings(file, B_WRITE_ONLY | B_CREATE_FILE + | B_ERASE_FILE); + if (status < B_OK) + return status; + + BMessage settings('chrm'); + status = settings.AddRect("window frame", Frame()); + if (status != B_OK) + return status; + + if (status == B_OK) { + status = settings.AddBool("show private blocks", + fCharacterView->IsShowingPrivateBlocks()); + } + if (status == B_OK) { + status = settings.AddBool("show contained blocks only", + fCharacterView->IsShowingContainedBlocksOnly()); + } + + if (status == B_OK) { + BFont font = fCharacterView->CharacterFont(); + status = settings.AddInt32("font size", font.Size()); + + font_family family; + font_style style; + if (status == B_OK) + font.GetFamilyAndStyle(&family, &style); + if (status == B_OK) + status = settings.AddString("font family", family); + if (status == B_OK) + status = settings.AddString("font style", style); + } + + if (status == B_OK) + status = settings.Flatten(&file); + + return status; +} + + +void +CharacterWindow::_SetFont(const char* family, const char* style) +{ + BFont font = fCharacterView->CharacterFont(); + font.SetFamilyAndStyle(family, style); + + fCharacterView->SetCharacterFont(font); +} + + +BMenu* +CharacterWindow::_CreateFontMenu() +{ + BMenu* menu = new BMenu("Font"); + + font_family currentFamily; + font_style currentStyle; + be_plain_font->GetFamilyAndStyle(¤tFamily, ¤tStyle); + + int32 numFamilies = count_font_families(); + + for (int32 i = 0; i < numFamilies; i++) { + font_family family; + if (get_font_family(i, &family) == B_OK) { + BMenu* subMenu = new BMenu(family); + menu->AddItem(new BMenuItem(subMenu, + new BMessage(kMsgFontSelected))); + + int numStyles = count_font_styles(family); + for (int32 j = 0; j < numStyles; j++) { + font_style style; + uint32 flags; + if (get_font_style(family, j, &style, &flags) == B_OK) { + BMenuItem* item = new BMenuItem(style, + new BMessage(kMsgFontSelected)); + subMenu->AddItem(item); + + if (!strcmp(family, currentFamily) + && !strcmp(style, currentStyle)) { + fSelectedFontItem = item; + item->SetMarked(true); + } + } + } + } + } + + return menu; +} + + +void +CharacterWindow::_UpdateUnicodeBlocks() +{ + for (int32 i = 0; i < fUnicodeBlockView->CountItems(); i++) { + BStringItem* item + = static_cast(fUnicodeBlockView->ItemAt(i)); + + bool enabled = fCharacterView->IsShowingBlock(i); + + if (item->IsEnabled() != enabled) { + item->SetEnabled(enabled); + fUnicodeBlockView->InvalidateItem(i); + } + } +} + + +void +CharacterWindow::_CreateUnicodeBlocks() +{ + float minWidth = 0; + for (uint32 i = 0; i < kNumUnicodeBlocks; i++) { + BStringItem* item = new BStringItem(kUnicodeBlocks[i].name); + fUnicodeBlockView->AddItem(item); + + float width = fUnicodeBlockView->StringWidth(item->Text()); + if (minWidth < width) + minWidth = width; + } + + fUnicodeBlockView->SetExplicitMinSize(BSize(minWidth / 2, 32)); + // TODO: why is this ignored? + fUnicodeBlockView->SetExplicitMaxSize(BSize(minWidth, B_SIZE_UNSET)); + + _UpdateUnicodeBlocks(); +} + diff --git a/src/apps/charactermap/CharacterWindow.h b/src/apps/charactermap/CharacterWindow.h new file mode 100644 index 0000000000..e8e724fea4 --- /dev/null +++ b/src/apps/charactermap/CharacterWindow.h @@ -0,0 +1,45 @@ +/* + * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ +#ifndef CHARACTER_WINDOW_H +#define CHARACTER_WINDOW_H + + +#include +#include + +class BFile; +class BListView; +class BMenu; +class BMenuItem; +class BSlider; +class CharacterView; + + +class CharacterWindow : public BWindow { +public: + CharacterWindow(); + virtual ~CharacterWindow(); + + virtual void MessageReceived(BMessage* message); + virtual bool QuitRequested(); + +private: + status_t _OpenSettings(BFile& file, uint32 mode); + status_t _LoadSettings(BMessage& settings); + status_t _SaveSettings(); + + void _SetFont(const char* family, const char* style); + BMenu* _CreateFontMenu(); + void _UpdateUnicodeBlocks(); + void _CreateUnicodeBlocks(); + +private: + BListView* fUnicodeBlockView; + CharacterView* fCharacterView; + BMenuItem* fSelectedFontItem; + BSlider* fFontSizeSlider; +}; + +#endif // CHARACTER_WINDOW_H diff --git a/src/apps/charactermap/Jamfile b/src/apps/charactermap/Jamfile new file mode 100644 index 0000000000..7625633fa2 --- /dev/null +++ b/src/apps/charactermap/Jamfile @@ -0,0 +1,15 @@ +SubDir HAIKU_TOP src apps charactermap ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders shared system ; + +Application CharacterMap : + CharacterMap.cpp + CharacterView.cpp + CharacterWindow.cpp + UnicodeBlocks.cpp + + : be + : CharacterMap.rdef + ; diff --git a/src/apps/charactermap/UnicodeBlocks.cpp b/src/apps/charactermap/UnicodeBlocks.cpp new file mode 100644 index 0000000000..0836ded89a --- /dev/null +++ b/src/apps/charactermap/UnicodeBlocks.cpp @@ -0,0 +1,195 @@ +/* + * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include "UnicodeBlocks.h" + + +const unicode_block kNoBlock; + +const struct unicode_block_entry kUnicodeBlocks[] = { + {"Basic Latin", 0x0000, 0x007f, false, B_BASIC_LATIN_BLOCK}, + {"Latin-1 Supplement", 0x0080, 0x00ff, false, B_LATIN1_SUPPLEMENT_BLOCK}, + {"Latin Extended A", 0x0100, 0x017f, false, B_LATIN_EXTENDED_A_BLOCK}, + {"Latin Extended B", 0x0180, 0x024f, false, B_LATIN_EXTENDED_B_BLOCK}, + {"IPA Extensions", 0x0250, 0x02af, false, B_IPA_EXTENSIONS_BLOCK}, + {"Spacing Modifier Letters", 0x02b0, 0x02ff, false, + B_SPACING_MODIFIER_LETTERS_BLOCK}, + {"Combining Diacritical Marks", 0x0300, 0x036f, false, + B_COMBINING_DIACRITICAL_MARKS_BLOCK}, + {"Greek and Coptic", 0x0370, 0x03ff, false, + B_BASIC_GREEK_BLOCK | B_GREEK_SYMBOLS_AND_COPTIC_BLOCK}, + {"Cyrillic", 0x0400, 0x04ff, false, B_CYRILLIC_BLOCK}, + {"Cyrillic Supplement", 0x0500, 0x052f, false, B_CYRILLIC_BLOCK}, + {"Armenian", 0x0530, 0x058f, false, B_ARMENIAN_BLOCK}, + {"Hebrew", 0x0590, 0x05ff, false, + B_BASIC_HEBREW_BLOCK | B_HEBREW_EXTENDED_BLOCK}, + {"Arabic", 0x0600, 0x06ff, false, + B_BASIC_ARABIC_BLOCK | B_ARABIC_EXTENDED_BLOCK}, + {"Syriac", 0x0700, 0x074f, false, kNoBlock}, + {"Arabic Supplement", 0x0750, 0x077f, false, kNoBlock}, + {"Thaana", 0x0780, 0x07bf, false, kNoBlock}, + {"N'Ko", 0x07c0, 0x07ff, false, kNoBlock}, + {"Devanagari", 0x0900, 0x097f, false, B_DEVANAGARI_BLOCK}, + {"Bengali", 0x0980, 0x09ff, false, B_BENGALI_BLOCK}, + {"Gurmukhi", 0x0a00, 0x0a7f, false, B_GURMUKHI_BLOCK}, + {"Gujarati", 0x0a80, 0x0aff, false, B_GUJARATI_BLOCK}, + {"Oriya", 0x0b00, 0x0b7f, false, B_ORIYA_BLOCK}, + {"Tamil", 0x0b80, 0x0bff, false, B_TAMIL_BLOCK}, + {"Telugu", 0x0c00, 0x0c7f, false, B_TELUGU_BLOCK}, + {"Kannada", 0x0c80, 0x0cff, false, B_KANNADA_BLOCK}, + {"Malayalam", 0x0d00, 0x0d7f, false, B_MALAYALAM_BLOCK}, + {"Sinhala", 0x0d80, 0x0dff, false, kNoBlock}, + {"Thai", 0x0e00, 0x0e7f, false, B_THAI_BLOCK}, + {"Lao", 0x0e80, 0x0eff, false, B_LAO_BLOCK}, + {"Tibetan", 0x0f00, 0x0fff, false, kNoBlock}, + {"Myanmar", 0x1000, 0x109f, false, kNoBlock}, + {"Georgian", 0x10a0, 0x10ff, false, B_BASIC_GEORGIAN_BLOCK}, + {"Hangul Jamo", 0x1100, 0x11ff, false, kNoBlock}, +// TODO! + {"Ethiopic", 0x1200, 0x137f, false, kNoBlock}, + {"Ethiopic Supplement", 0x1380, 0x139f, false, kNoBlock}, + {"Cherokee", 0x13a0, 0x13ff, false, kNoBlock}, + {"Unified Canadian Aboriginal Syllabics", 0x1400, 0x167f, false, kNoBlock}, + {"Ogham", 0x1680, 0x169f, false, kNoBlock}, + {"Runic", 0x16a0, 0x16ff, false, kNoBlock}, + {"Tagalog", 0x1700, 0x171f, false, kNoBlock}, + {"Hanunoo", 0x1720, 0x173f, false, kNoBlock}, + {"Buhid", 0x1740, 0x175f, false, kNoBlock}, + {"Tagbanwa", 0x1760, 0x177f, false, kNoBlock}, + {"Khmer", 0x1780, 0x17ff, false, kNoBlock}, + {"Mongolian", 0x1800, 0x18af, false, kNoBlock}, + {"Limbu", 0x1900, 0x194f, false, kNoBlock}, + {"Tai Le", 0x1950, 0x197f, false, kNoBlock}, + {"New Tai Lue", 0x1980, 0x19df, false, kNoBlock}, + {"Khmer Symbols", 0x19e0, 0x19ff, false, kNoBlock}, + {"Buginese", 0x1a00, 0x1a1f, false, kNoBlock}, + {"Balinese", 0x1b00, 0x1b7f, false, kNoBlock}, + {"Sundanese", 0x1b80, 0x1bbf, false, kNoBlock}, + {"Lepcha", 0x1c00, 0x1c4f, false, kNoBlock}, + {"Ol Chiki", 0x1c50, 0x1c7f, false, kNoBlock}, + {"Phonetic Extensions", 0x1d00, 0x1d7f, false, kNoBlock}, + {"Phonetic Extensions Supplement", 0x1d80, 0x1dbf, false, kNoBlock}, + {"Combining Diacritical Marks Supplement", 0x1dc0, 0x1dff, false, kNoBlock}, + {"Latin Extended Additional", 0x1e00, 0x1eff, false, kNoBlock}, + {"Greek Extended", 0x1f00, 0x1fff, false, kNoBlock}, + {"General Punctuation", 0x2000, 0x206f, false, kNoBlock}, + {"Superscripts and Subscripts", 0x2070, 0x209f, false, kNoBlock}, + {"Currency Symbols", 0x20a0, 0x20cf, false, kNoBlock}, + {"Combining Diacritical Marks for Symbols", 0x20d0, 0x20ff, false, + kNoBlock}, + {"Letterlike Symbols", 0x2100, 0x214f, false, kNoBlock}, + {"Number Forms", 0x2150, 0x218f, false, kNoBlock}, + {"Arrows", 0x2190, 0x21ff, false, kNoBlock}, + {"Mathematical Operators", 0x2200, 0x22ff, false, kNoBlock}, + {"Miscellaneous Technical", 0x2300, 0x23ff, false, kNoBlock}, + {"Control Pictures", 0x2400, 0x243f, false, kNoBlock}, + {"Optical Character Recognition", 0x2440, 0x245f, false, kNoBlock}, + {"Enclosed Alphanumerics", 0x2460, 0x24ff, false, kNoBlock}, + {"Box Drawing", 0x2500, 0x257f, false, kNoBlock}, + {"Block Elements", 0x2580, 0x259f, false, kNoBlock}, + {"Geometric Shapes", 0x25a0, 0x25ff, false, kNoBlock}, + {"Miscellaneous Symbols", 0x2600, 0x26ff, false, kNoBlock}, + {"Dingbats", 0x2700, 0x27bf, false, kNoBlock}, + {"Miscellaneous Mathematical Symbols A", 0x27c0, 0x27ef, false, kNoBlock}, + {"Supplemental Arrows A", 0x27f0, 0x27ff, false, kNoBlock}, + {"Braille Patterns", 0x2800, 0x28ff, false, kNoBlock}, + {"Supplemental Arrows B", 0x2900, 0x297f, false, kNoBlock}, + {"Miscellaneous Mathematical Symbols B", 0x2980, 0x29ff, false, kNoBlock}, + {"Supplemental Mathematical Operators", 0x2a00, 0x2aff, false, kNoBlock}, + {"Miscellaneous Symbols And Arrows", 0x2b00, 0x2bff, false, kNoBlock}, + {"Glagotic", 0x2c00, 0x2c5f, false, kNoBlock}, + {"Latin Extended C", 0x2c60, 0x2c7f, false, kNoBlock}, + {"Coptic", 0x2c80, 0x2cff, false, kNoBlock}, + {"Georgian Supplement", 0x2d00, 0x2d2f, false, kNoBlock}, + {"Tifinagh", 0x2d30, 0x2d7f, false, kNoBlock}, + {"Ethiopic Extended", 0x2d80, 0x2ddf, false, kNoBlock}, + {"Cyrillic Extended A", 0x2de0, 0x2dff, false, kNoBlock}, + {"Supplement Punctuation", 0x2e00, 0x2e7f, false, kNoBlock}, + {"CJK Radicals Supplement", 0x2e80, 0x2eff, false, kNoBlock}, + {"Kangxi Radicals", 0x2f00, 0x2fdf, false, kNoBlock}, + {"Ideographic Description Characters", 0x2ff0, 0x2fff, false, kNoBlock}, + {"CJK Symbols and Punctuation", 0x3000, 0x303f, false, kNoBlock}, + {"Hiragana", 0x3040, 0x309f, false, kNoBlock}, + {"Katakana", 0x30a0, 0x30ff, false, kNoBlock}, + {"Bopomofo", 0x3100, 0x312f, false, kNoBlock}, + {"Hangul Compatibility Jamo", 0x3130, 0x318f, false, kNoBlock}, + {"Kanbun", 0x3190, 0x319f, false, kNoBlock}, + {"Bopomofo Extended", 0x31a0, 0x31bf, false, kNoBlock}, + {"CJK Strokes", 0x31c0, 0x31ef, false, kNoBlock}, + {"Katakana Phonetic Extensions", 0x31f0, 0x31ff, false, kNoBlock}, + {"Enclosed CJK Letters and Months", 0x3200, 0x32ff, false, kNoBlock}, + {"CJK Compatibility", 0x3300, 0x33ff, false, kNoBlock}, + {"CJK Unified Ideographs Extension A", 0x3400, 0x4dbf, false, kNoBlock}, + {"Yijing Hexagram Symbols", 0x4dc0, 0x4dff, false, kNoBlock}, + {"CJK Unified Ideographs", 0x4e00, 0x9fff, false, kNoBlock}, + {"Yi Syllables", 0xa000, 0xa48f, false, kNoBlock}, + {"Yi Radicals", 0xa490, 0xa4cf, false, kNoBlock}, + {"Vai", 0xa500, 0xa63f, false, kNoBlock}, + {"Cyrillic Extended B", 0xa640, 0xa69f, false, kNoBlock}, + {"Modifier Tone Letters", 0xa700, 0xa71f, false, kNoBlock}, + {"Lating Extended D", 0xa720, 0xa7ff, false, kNoBlock}, + {"Syloti Nagri", 0xa800, 0xa82f, false, kNoBlock}, + {"Phags-pa", 0xa840, 0xa87f, false, kNoBlock}, + {"Saurashtra", 0xa880, 0xa8df, false, kNoBlock}, + {"Kayah Li", 0xa900, 0xa92f, false, kNoBlock}, + {"Rejang", 0xa930, 0xa95f, false, kNoBlock}, + {"Cham", 0xaa00, 0xaa5f, false, kNoBlock}, + {"Hangul Syllables", 0xac00, 0xd7af, false, kNoBlock}, +// {"High Surrogates", 0xd800, 0xdb7f, false, kNoBlock}, +// {"High Private Use Surrogates", 0xdb80, 0xdbff, false, kNoBlock}, +// {"Low Surrogates", 0xdc00, 0xdfff, false, kNoBlock}, + {"Private Use Area", 0xe000, 0xf8ff, true, kNoBlock}, + {"CJK Compatibility Ideographs", 0xf900, 0xfaff, false, kNoBlock}, + {"Alphabetic Presentation Forms", 0xfb00, 0xfb4f, false, kNoBlock}, + {"Arabic Presentation Forms A", 0xfb50, 0xfdff, false, kNoBlock}, + {"Variation Selectors", 0xfe00, 0xfe0f, false, kNoBlock}, + {"Vertical Forms", 0xfe10, 0xfe1f, false, kNoBlock}, + {"Combining Half Marks", 0xfe20, 0xfe2f, false, kNoBlock}, + {"CJK Compatibility Forms", 0xfe30, 0xfe4f, false, kNoBlock}, + {"Small Form Variants", 0xfe50, 0xfe6f, false, kNoBlock}, + {"Arabic Presentation Forms B", 0xfe70, 0xfeff, false, kNoBlock}, + {"Halfwidth and Fullwidth Forms", 0xff00, 0xffef, false, kNoBlock}, + {"Specials", 0xfff0, 0xffff, false, kNoBlock}, + {"Linear B Syllabary", 0x010000, 0x01007f, false, kNoBlock}, + {"Linear B Ideograms", 0x010080, 0x0100ff, false, kNoBlock}, + {"Aegean Numbers", 0x010100, 0x01013f, false, kNoBlock}, + {"Ancient Greek Numbers", 0x010140, 0x01018f, false, kNoBlock}, + {"Ancient Symbols", 0x010190, 0x0101cf, false, kNoBlock}, + {"Phaistos Disc", 0x0101d0, 0x0101ff, false, kNoBlock}, + {"Lycian", 0x010280, 0x01029f, false, kNoBlock}, + {"Carian", 0x0102a0, 0x0102df, false, kNoBlock}, + {"Old Italic", 0x010300, 0x01032f, false, kNoBlock}, + {"Gothic", 0x010330, 0x01034f, false, kNoBlock}, + {"Ugaritic", 0x010380, 0x01039f, false, kNoBlock}, + {"Old Persian", 0x0103a0, 0x0103df, false, kNoBlock}, + {"Deseret", 0x010400, 0x01044f, false, kNoBlock}, + {"Shavian", 0x010450, 0x01047f, false, kNoBlock}, + {"Osmanya", 0x010480, 0x0104af, false, kNoBlock}, + {"Cypriot Syllabary", 0x010800, 0x01083f, false, kNoBlock}, + {"Phoenician", 0x010900, 0x01091f, false, kNoBlock}, + {"Lydian", 0x010920, 0x01093f, false, kNoBlock}, + {"Kharoshthi", 0x010a00, 0x010a5f, false, kNoBlock}, + {"Cuneiform", 0x012000, 0x0123ff, false, kNoBlock}, + {"Cuneiform Numbers and Punctuation", 0x012400, 0x01247f, false, kNoBlock}, + {"Byzantine Musical Symbols", 0x01d000, 0x01d0ff, false, kNoBlock}, + {"Muscial Symbols", 0x01d100, 0x01d1ff, false, kNoBlock}, + {"Ancient Greek Musical Notation", 0x01d200, 0x01d24f, false, kNoBlock}, + {"Tai Xuan Jing Symbols", 0x01d300, 0x01d35f, false, kNoBlock}, + {"Counting Rod Numerals", 0x01d360, 0x01d37f, false, kNoBlock}, + {"Mathematical Alphanumeric Symbols", 0x01d400, 0x01d7ff, false, kNoBlock}, + {"Mahjong Tiles", 0x01f000, 0x01f02f, false, kNoBlock}, + {"Domino Tiles", 0x01f030, 0x01f09f, false, kNoBlock}, + {"CJK Unified Ideographs Extension B", 0x020000, 0x02a6df, false, kNoBlock}, + {"CJK Compatibility Ideographs Supplement", 0x02f800, 0x02fa1f, false, + kNoBlock}, + {"Tags", 0x0e0000, 0x0e007f, false, kNoBlock}, + {"Variation Selectors Supplement", 0x0e0100, 0x0e01ef, false, kNoBlock}, + {"Supplementary Private Use Area A", 0x0f0000, 0x0fffff, true, kNoBlock}, + {"Supplementary Private Use Area B", 0x100000, 0x10ffff, true, kNoBlock}, +}; + +const uint32 kNumUnicodeBlocks + = sizeof(kUnicodeBlocks) / sizeof(kUnicodeBlocks[0]); diff --git a/src/apps/charactermap/UnicodeBlocks.h b/src/apps/charactermap/UnicodeBlocks.h new file mode 100644 index 0000000000..4c6b99cdfb --- /dev/null +++ b/src/apps/charactermap/UnicodeBlocks.h @@ -0,0 +1,26 @@ +/* + * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ +#ifndef UNICODE_BLOCKS_H +#define UNICODE_BLOCKS_H + + +#include + + +struct unicode_block_entry { + const char* name; + uint32 start; + uint32 end; + bool private_block; + const unicode_block& block; + + uint32 Count() const { return end + 1 - start; } +}; + +extern const unicode_block kNoBlock; +extern const struct unicode_block_entry kUnicodeBlocks[]; +extern const uint32 kNumUnicodeBlocks; + +#endif // UNICODE_BLOCKS_H