Windows의 공용 컨트롤 열전.
날짜/시간 컨트롤에 이어 오늘은 툴바(toolbar)라고 불리는 '도구상자/도구모음줄' 컨트롤에 대해서 좀 얘기를 해 보겠다.

메모장 같은 급의 초간단 프로그램이 아닌 이상, 표준 GUI 기반인 대다수의 프로그램들은 상단에 클릭 가능한 그림 버튼들이 가로로 쭉 늘어서 있다. 도구모음줄은 바로 그 그림 버튼들의 표시를 책임진다. 각 그림 내지 아이콘은 그 프로그램에서 자주 쓰이는 명령들을 나타내며, 이를 클릭하면 일일이 메뉴를 열어서 글자 형태로 된 명령문을 읽고 선택하는 것보다 명령을 더 빠르게 내릴 수 있다.
자주 쓰이는 명령에 대해서 키보드에 단축키가 있다면 마우스에는 도구모음줄이 있는 셈이다.

사용자 삽입 이미지

사실, 도구모음줄은 컴퓨터의 성능 관점에서는 그렇게 효율적인 도구가 아닐지도 모른다. 요즘이야 제약이 덜해지긴 했지만, 과거에 화면 해상도가 충분하지 못하던 시절에는 텍스트나 그림 같은 문서 컨텐츠를 한 줄 표시할 공간이 아까운데 도구모음줄을 늘어놓는 건 화면 낭비였다. 수십 종류에 달하는 명령 아이콘들도 다 메모리를 수십 KB 이상씩 잡아먹는다는 건 역시 두 말할 나위가 없고.

하지만 어떤 프로그램을 실행했더니 그냥 빈 화면에 cursor만 달랑 깜빡이는 것보다는, 아무래도 컬러풀한 아이콘들이 가득한 도구모음줄 하나라도 좀 놓여 있는 게 사용자에게 친근하다. 이것이 마우스 사용자에게는 뭔가 클릭할 거리를 제공함으로써 프로그램을 더 편리하게 사용하는 데 실질적인 도움이 된다.

1990년대 초, Windows 3.x 시절에도 MS Word나 Excel의 까마득한 옛날 버전을 보면 파일, 편집, 보기 같은 자주 쓰인 명령이 등재된 도구모음줄이 있었다. 도구모음줄이라는 개념은 그때 처음으로 등장한 것으로 보인다. 그 시절에는 도구모음줄은 자체 구현이었고 MFC조차도 그걸 자체 구현해 줬었는데, Windows 95로 넘어오면서 운영체제의 공용 컨트롤로 형태가 바뀌었다. MFC의 ToolBar 클래스도 4.0 32비트 버전부터는 운영체제가 제공하는 놈을 쓰는 걸로 형태가 바뀌었다.

그리고 1990년대 말, MS Office 97부터는 버튼의 모양이 마우스로 가리키고 있는 놈만 얇은 입체 테두리가 나타나는 flat 스타일로 바뀌었으며, 메뉴도 도구모음줄 버튼이 있는 명령은 왼쪽에 그 도구모음줄 아이콘이 같이 뜨게 되었다. 이건 당시로서는 나름 굉장히 참신한 디자인이었다.
Office야 운영체제의 표준 GUI를 안 쓰는 걸로 악명(?)이 높았으니, flat 스타일은 Windows 98 타이밍 때 공용 컨트롤에도 도입되었다.

사용자 삽입 이미지

운영체제 차원에서 공용 컨트롤이 등장했으니 Visual C++과 MFC가 독자적으로 하는 일은 이제 없어졌느냐 하면 여전히 그렇지 않다. MFC가 하는 일은 다음과 같다.
(1) 먼저, 도구모음줄의 컨테이너격인 Control bar를 제공한다. 도구모음줄의 폭을 자유롭게 지정하고 위치도 자유롭게 옮기고 심지어 부모 윈도우의 상하좌우 등 어디든 자유롭게 붙이거나 떼는 것은 운영체제가 알아서 해 주는 일이 아니다. MFC의 도움 없이 직접 구현하는 건 머리에 쥐가 나는 노가다이다. 심지어 드래그하기 편하게 왼쪽에 그려 주는 gripper 세로줄 공간도 MFC가 그려 준 결과물이다.

개발하는 프로그램이 덩치가 MS 오피스 내지 포토샵 같은 상업용 프로그램 급으로 커지면 도구모음줄이 2개 이상 존재하게 된다. 보기 메뉴의 '도구모음줄' 항목은 체크 하나만 달랑 있는 게 아니라 '표준, 서식, 그리기' 등 도구모음줄의 종류를 가리키는 부메뉴를 갖게 된다.
도구모음줄이 하나밖에 없을 때는 겨우 그것만 이리저리 옮기고 붙였다 떼는 기능이 좀 잉여스럽게 느껴지겠지만, 그게 여러 개가 존재하게 되면 이들의 위치를 관리하는 기능은 필수가 된다. MFC는 그런 필수 기능을 구현해 준다.

도구모음줄이 한두 개도 아니고 무려 10~20개씩 달려 있는 방대한 프로그램은 도구모음줄의 버튼들을 사용자 정의(customize)하는 기능도 전문적으로 갖추고 있다. 공용 컨트롤이 기본으로 제공하는 customize 기능도 있지만, 그건 전체 아이콘들 집합에서 자기 도구모음줄에다가 추가할 버튼을 선택하고 순서를 바꾸는 것 정도가 전부이다. 그 반면 MS Office의 경우, 2007 이전 버전은 메뉴의 텍스트, 도구모음줄의 버튼 그림까지 전부 사용자가 바꿀 수 있어서 가히 개발자의 근성을 짐작케 하는 엄청난 customize 기능을 제공했다. 나중에는 MS Office는 리본 UI 기반으로 바뀌고 Visual Studio도 WPF 기반으로 UI가 싹 바뀌면서 이런 기능은 더 찾아보기 어렵게 됐다.

이런 컨테이너 기능 말고도 또 Visual C++가 MFC와 연계하여 제공하는 기능은 바로 (2) IDE가 제공하는 리소스 편집기이다.
MFC로 응용 프로그램을 만든다면 우리는 리소스 편집기를 이용해서 리소스에다가 Toolbar를 추가하고 도구 버튼과 아이콘, 연계 명령들을 넣곤 한다. 그런데 이 Toolbar라는 리소스 카테고리는 Windows가 제공하는 표준 리소스 포맷이 아니다. 비트맵, 아이콘, 메뉴, 문자열과는 달리 표준 포맷이 아니며, MFC가 자체적으로 정의해서 사용하는 포맷이다. 여기에 지정된 데이터를 바탕으로 도구모음줄을 초기화하는 것은 응당 MFC의 몫이다. LoadIcon, LoadMenu, LoadString 따위와는 달리, LoadToolBar는 MFC 클래스의 멤버 함수로나 존재하지 Windows API에는 없다.

게다가 이 toolbar 리소스는 단독으로 있는 것도 아니다. 얘가 정의하는 것은 한 도구모음줄에 몇 개의 버튼이 있고 각 버튼이 의미하는 명령 ID는 무엇인지, 혹은 이것이 구분자인지 같은 정보가 전부이다. 그 도구모음줄이 참조하는 비트맵은 같은 ID의 Bitmap 리소스에 있다.
하지만 Visual C++ IDE는 도구모음줄과 연계하는 비트맵은 비록 비트맵이라 할지라도 표준 비트맵 리소스에서 따로 표시를 하지 않으며, 그 비트맵은 도구모음줄 리소스를 편집하는 곳에서 버튼 구조와 함께 편집하게 돼 있다. 프로그램이 내부적으로 이런 보정 처리까지 하고 있는 것이다.

내부적으로 MFC는 한 프로그램 윈도우에 대해서 한 리소스 ID를 부여하여 이걸로 문자열(프로그램 제목), 아이콘, 액셀러레이터 단축키, 표준 도구모음줄(비트맵 포함)까지 한데 관리를 하기까지 한다. 이것이 바로 CFrameWnd::LoadFrame 함수가 하는 일이다. 참 대단한 발상이다.

다음으로, 도구모음줄에 대해서 프로그래머가 반드시 짚고 넘어가야 할 기술적인 사항이 하나 있다.
도구모음줄의 버튼 그림은 작고 아담한 게 아이콘을 닮았지만, 실제로 이건 아이콘이나 마우스 포인터와는 달리 그냥 비트맵이다.
'아이콘'은 이미지 비트맵과 마스크 비트맵으로 구성되어서 태생적으로 래스터 오퍼레이션을 통해 투명 배경이나 반전 같은 걸 표현할 수 있다. 그러나 이미지 비트맵 한 장만 갖고는 그런 걸 표현할 수 없다. 그렇다면 도구모음줄 버튼은 어떤 방식으로 투명색을 표현하는 걸까?

이 방식은 생각보다 굉장히 원시적이고 단순무식하다. TB_ADDBITMAP 메시지라는 재래식 방식을 쓰는 경우, 도구모음줄은 이미지 비트맵 한 장만 달랑 받아들이고 투명 처리 같은 걸 해 주지 않는다. 비트맵을 생으로 있는 그대로 출력만 한다.
그렇기 때문에 MFC의 도구모음줄 클래스는 자신의 리소스 비트맵 이미지에 대해서 보정을 한다. 비트맵에 RGB(192,192,192)에 속하는 은색/회색 픽셀이 있으면 그걸 현재 운영체제의 COLOR_BTNFACE 시스템 컬러로 바꾸고, 은색 말고도 짙은 회색이나 검정, 하양은 그에 상응하는 시스템 컬러로 바꾼다. 그렇게 보정된 비트맵을 도구모음줄로 보내서 은색이 편의상 투명 배경색인 것처럼 보이게 한다. 보정을 안 하면 바로 이런 꼴 난다..;;

사용자 삽입 이미지

시스템 색상이 바뀌어서 WM_SYSCOLORCHANGE 메시지가 오면? 당연히 도구모음줄 비트맵도 매번 다시 만들어서 지정한다.
MFC를 뒤져 보면 이 일을 하는 AfxLoadSysColorBitmap라는 함수가 bartool.cpp에 있다. 아니, 이렇게 색깔 치환을 한 비트맵을 생성하는 함수가 Windows 95 시절부터 comctl32.dll에 CreateMappedBitmap이라고 있어 왔다. 도구모음줄 전용이기 때문에 user32도, gdi32도 아닌 comctl32에 있는 것이다.

그리고 이런 색깔 보정이 마냥 삽질인 것만은 아닌 것이..
시스템 색상이 고대비 검정 같은 걸로 바뀌었을 때는 검은색을 흰색으로 바꾸는 작업도 어차피 필요하기 때문이다. 도구모음줄의 비트맵은 반쯤은 이런 유동적인 환경 변화에도 대비가 돼 있어야 한다는 점이 흥미롭다.

도구모음줄용 비트맵으로 원시적인 생 비트맵뿐만 아니라 image list를 지정하는 TB_SETIMAGELIST 메시지는 Internet Explorer 4는 아니고 3과 함께 약간 나중에 추가됐다.
image list는 자체적으로 마스크 정보도 포함할 수 있으니 예전보다는 상황이 좀 낫다. 또한 ImageList_LoadImage 함수는 은색이 아닌 임의의 색깔을 투명색으로 지정할 수 있고, 아예 default로 (0,0) 화면 최상단 좌측 픽셀을 투명색으로 지정하게 할 수도 있다.
평소에는 흑백 이미지이다가 마우스 포인터가 가리키고 있는 버튼만 컬러 이미지로 출력하는 일명 hot image를 지정하는 것은 이렇게 image list 형태로만 지정 가능하다.

이렇게 특정 한 색깔을 투명색으로 끌어다 쓰는 건 아무래도 16색/256색 시절의 그래픽 패러다임을 벗어나지 못한 발상이다. MFC feature pack을 이용해서 트루컬러 아이콘이 들어간 도구모음줄을 만들면 당장은 보기 좋지만 시스템 색상을 고대비 검정으로 바꿔 보면 경계가 완전 뭉개지고 보기 좋지 않은 걸 알 수 있다. 어느 배경색에도 경계가 부드럽게 나오려면 근본적으로 알파채널이 쓰여야 할 텐데 그렇지 못하기 때문이다.

요컨대 오늘날 도구모음줄은 아이콘들이 그런 것처럼 트루컬러와 알파 채널에 대비가 돼 있어야 하고, 그러면서 고대비 모드도 지원해야 하며, 더 욕심을 부리자면 고해상도 DPI에서는 약간 큰 비트맵도 준비돼 있어야 한다. MS Office의 리본 UI는 고대비 모드에서는 그냥 16컬러로 간략화한 비트맵을 대신 출력하는 것 같다.
그리고 <날개셋> 편집기는 겨우 그 덩치의 프로그램에서 저런 것까지 일일이 대비하는 건 너무 낭비라 여겨지기 때문에 도구모음줄의 아이콘은 그냥 16*16 크기의 16색에 머물러 있다.. ^^

그나저나,

  • 공용 컨트롤을 쓰지 않고 자체 구현된 도구모음줄은 대화상자를 띄우는 명령을 클릭한 경우, 대화상자가 떠 있는 동안에 버튼이 여전히 눌러져 있기도 했던 것 같다. MS Office 2007 이전의 옛 버전과 Visual C++ 6 등이 그 예다.
  • 전무후무하게 도구모음줄 배경에 solid color가 아니라 무늬가 있었던 IE 3의 도구모음줄은 어떻게 구현되었는지가 새삼 궁금해진다. 얘는 표준 공용 컨트롤 기반인데, 아마 얘 때문에 image list 기능이 도입되었지 싶다. 이쯤 되면 버튼 비트맵에 자체적으로 마스크 정보가 있어야만 도구모음줄 배경과도 합성이 가능하지 않았겠는가.

사용자 삽입 이미지

사용자 삽입 이미지

Posted by 사무엘

2015/11/16 08:36 2015/11/16 08:36
, ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1160

Trackback URL : http://moogi.new21.org/tc/trackback/1160

Leave a comment
« Previous : 1 : ... 1180 : 1181 : 1182 : 1183 : 1184 : 1185 : 1186 : 1187 : 1188 : ... 2204 : Next »

블로그 이미지

그런즉 이제 애호박, 단호박, 늙은호박 이 셋은 항상 있으나, 그 중에 제일은 늙은호박이니라.

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2024/11   »
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

Site Stats

Total hits:
2985417
Today:
970
Yesterday:
2184