root/src/add-ons/input_server/devices/virtualkeyboard/VirtualKeyboardWindow.cpp
/*
 * Copyright 2014 Freeman Lou <freemanlou2430@yahoo.com>
 * All rights reserved. Distributed under the terms of the MIT license.
 */
#include "VirtualKeyboardWindow.h"

#include <Directory.h>
#include <Entry.h>
#include <FindDirectory.h>
#include <GroupLayoutBuilder.h>
#include <ListView.h>
#include <Locale.h>
#include <Menu.h>
#include <MenuItem.h>
#include <Path.h>
#include <Screen.h>

#include "KeyboardLayoutView.h"
#include "KeymapListItem.h"

static const uint32 kMsgMenuFontChange = 'mMFC';

static int
compare_key_list_items(const void* a, const void* b)
{
        KeymapListItem* item1 = *(KeymapListItem**)a;
        KeymapListItem* item2 = *(KeymapListItem**)b;

        return BLocale::Default()->StringCompare(item1->Text(), item2->Text());
}


VirtualKeyboardWindow::VirtualKeyboardWindow(BInputServerDevice* dev)
        :
        BWindow(BRect(0, 0, 0, 0), "Virtual Keyboard", B_NO_BORDER_WINDOW_LOOK,
                B_FLOATING_ALL_WINDOW_FEEL, B_WILL_ACCEPT_FIRST_CLICK | B_AVOID_FOCUS),
        fDevice(dev)
{
        BScreen screen;
        BRect screenRect(screen.Frame());
        ScreenChanged(screenRect, screen.ColorSpace());

        SetLayout(new BGroupLayout(B_VERTICAL));

        // Add to an options window later, use as list for now
        fMapListView = new BListView("Maps");
        fFontMenu = new BMenu("Font");
        fLayoutMenu = new BMenu("Layout");

        _LoadMaps();
        _LoadLayouts(fLayoutMenu);
        _LoadFonts();

        fCurrentKeymap.SetToCurrent();

        fKeyboardView = new KeyboardLayoutView("Keyboard", fDevice);
        fKeyboardView->GetKeyboardLayout()->SetDefault();
        fKeyboardView->SetKeymap(&fCurrentKeymap);

        AddChild(BGroupLayoutBuilder(B_VERTICAL).Add(fKeyboardView));
}


void
VirtualKeyboardWindow::_LoadLayouts(BMenu* menu)
{
        directory_which dataDirectories[] = {
                B_USER_NONPACKAGED_DATA_DIRECTORY,
                B_USER_DATA_DIRECTORY,
                B_SYSTEM_NONPACKAGED_DIRECTORY,
                B_SYSTEM_DATA_DIRECTORY,
        };

        for (uint i = 0; i < sizeof(dataDirectories) / sizeof(directory_which); i++) {
                BPath path;
                if (find_directory(dataDirectories[i], &path) != B_OK)
                        continue;

                path.Append("KeyboardLayouts");

                BDirectory directory;
                if (directory.SetTo(path.Path()) == B_OK)
                        _LoadLayoutMenu(menu, directory);
        }
}


void
VirtualKeyboardWindow::_LoadLayoutMenu(BMenu* menu, BDirectory directory)
{
        entry_ref ref;

        while (directory.GetNextRef(&ref) == B_OK) {
                if (menu->FindItem(ref.name) != NULL)
                        continue;

                BDirectory subdirectory;
                subdirectory.SetTo(&ref);
                if (subdirectory.InitCheck() == B_OK) {
                        BMenu* submenu = new BMenu(ref.name);
                        _LoadLayoutMenu(submenu, subdirectory);
                        menu->AddItem(submenu);
                } else {
                        // BMessage* message = new BMessage(kChangeKeyboardLayout);
                        // message->AddRed("ref",&ref);
                        menu->AddItem(new BMenuItem(ref.name, NULL));
                }
        }
}


void
VirtualKeyboardWindow::_LoadMaps()
{
        BPath path;
        if (find_directory(B_SYSTEM_DATA_DIRECTORY, &path) != B_OK)
                return;

        path.Append("Keymaps");
        BDirectory directory;
        entry_ref ref;

        if (directory.SetTo(path.Path()) == B_OK) {
                while (directory.GetNextRef(&ref) == B_OK) {
                        fMapListView->AddItem(new KeymapListItem(ref));
                }
        }
        fMapListView->SortItems(&compare_key_list_items);
}


void
VirtualKeyboardWindow::_LoadFonts()
{
        int32 numFamilies = count_font_families();
        font_family family, currentFamily;
        font_style currentStyle;
        uint32 flags;

        be_plain_font->GetFamilyAndStyle(&currentFamily, &currentStyle);

        for (int32 i = 0; i < numFamilies; i++) {
                if (get_font_family(i, &family, &flags) == B_OK) {
                        BMenuItem* item = new BMenuItem(family, NULL);  // new BMessage(kMsgMenuFontChanged));
                        fFontMenu->AddItem(item);
                        if (!strcmp(family, currentFamily))
                                item->SetMarked(true);
                }
        }
}


void
VirtualKeyboardWindow::MessageReceived(BMessage* message)
{
        if (message->what == kKeymapChange) {
                fCurrentKeymap.SetToCurrent();
                fKeyboardView->SetKeymap(&fCurrentKeymap);
        }
        BWindow::MessageReceived(message);
}


void
VirtualKeyboardWindow::ScreenChanged(BRect screenRect, color_space depth)
{
        ResizeTo(screenRect.Width(), screenRect.Height() / 3);
        MoveTo(0, screenRect.Height() - screenRect.Height() / 3);
}