Scintilla 구성요소 디자인 |
신틸라는 C++ 코드로 된 세 가지 주요 레이어로 구성된다.
이 구조의 주 목적은 플랫폼 종속적인 코드를 핵심 코드와 분리하는 것이다. 이렇게 하면 더 쉽게 신틸라를 새로운 플랫폼으로 이식할 수 있고 코드를 읽는 독자가 플랫폼 상세에 신경쓰지 않아도 된다. 이식 문제를 최소화하고 코드가 장황하게 커지는 것을 피하기 위해 신틸라에 보수적인 C++ 코드를 사용하였다. 그래서 예외 처리가 없으며, 실행 시간 유형 정보도 없으며, 표준 C++ 라이브러리를 사용하지 않고, 템플리트의 사용을 자제하였다.
현재 지원되는 플랫폼으로 윈도우즈, GTK+/Linux, Cocoa, Qt 그리고 wxWindows는 많은 면에서 상당히 비슷하다. 각 플랫폼은 창이 있고 메뉴와 비트맵이 있다. 이런 특징들은 일반적으로 비슷하게 작동한다. 그래서 각 플랫폼은 창을 이동하거나 빨간 줄을 그리는 방법이 있다. 어떤 경우 한 플랫폼은 호출 하나 보다는 일련의 호출을 요구한다. 또 어떤 경우는 차이가 더 심하다. 윈도우즈 클립보드를 읽는 일은 동기적으로 일어나지만, GTK+ 클립보드를 읽으려면 클립보드 데이터가 담긴 메시지로 비동기적으로 응답을 받는 요청 호출이 필요하다. wxWidgets 플랫폼은 wxWidgets 홈페이지에서 얻을 수 있다.
이 라이브러리는 플랫폼의 고유 능력을 감싼 상당히 작은 얇은 레이어이다.
이식 라이브러리는 Platform.h에 정의되어 있으며 각 플랫폼마다 하나씩 구현되어 있다. PlatWin.cxx에는 Windows 변종 메쏘드들이 정의되고 PlatGTK.cxx에는 GTK+ 변종들이 정의된다.
여기에서 클래스 중에는 플랫폼 종속적인 객체 식별자가 포함되며 이런 플랫폼 객체에 대한 프록시로 행위한다. 대부분의 클라이언트 코드는 그리하여 현재 플랫폼이 무엇인지 고민할 필요 없이 플랫폼 종속적인 객체를 다룰 수 있다. 가끔 클라이언트 코드가 그 아래의 객체 식별자에 접근할 필요가 있다. 이럴 경우 GetID 메쏘드가 제공된다. 플랫폼 종속적인 식별자의 아래 유형은 일반적인 이름으로 typedef 되어 있어서 필요할 경우 클라이언트 코드에 전송할 수 있다.
자주 사용되는 배치 지시어를 담기 위하여 제공되는 간단한 클래스이다. PRectangle은 자신의 하변과 우변을 포함하지 않는 Mac / Windows 관례를 따른다. 대신에 GTK+에서는 네 변을 모두 포함하는 것이 일반적이다. Rectangle로 부르지 않는데 이 이름은 윈도우즈에서 매크로의 이름일 가능성이 있기 때문이다.
Colour는 플랫폼 종속적인 색깔 식별자를 보유한다 - 윈도우즈라면 COLORREF이며 GTK+라면 GdkColor이다. 색깔을 구성하는 빨강, 초록 그리고 파랑 요소는 윈도우즈에서 8 비트 정밀도로 제한된다. ColourPairs는 가능한 색깔이 모두 언제나 사용가능한 것은 아니기 때문에 사용된다. 일반적으로 Windows 그리고 GTK+에서 설정되는, 8 비트 칼러 모드를 사용하면, 화면에 오직 256 칼러만 사용가능하다. 그리하여 어플리케이션에서 진한 빨강 #400000을 요구하면, #800000이나 #330000 같이 이미 사용가능한 컬러에만 할당될 뿐이다. 16 또는 2 컬러 모드로 심지어 더 적은 선택도 가능하다. 어플리케이션은 이미 사용가능한 컬러만으로 제한된 세트를 사용할 것이다.
Palette 객체는 색깔 쌍 집합이 담겨 있으며 플랫폼에서 결정한 것이 허용되는지 알아보고 이런 색깔을 할당하도록 적절하게 호출할 수 있다.기대하는 색깔을 담은 간단한 클래스이다. 내부적으로 32 비트 정수 하나로 표현된다. BGR 포맷으로 색깔 당 8 비트이다. 또 각 색상 요소를 따로따로 가져올 수 있도록 편리한 API를 제공한다. 플랫폼이 24 비트 깊이를 감당하지 못하면 정확하게 요구하는 색깔을 나타낼 수 없을 수 있다. 실제로 정확하게 요구하는 색깔을 나타낼 수 없을 수는 있지만 최대한 적절하게 가공처리해 준다.
폰트는 플랫폼 종속적인 폰트 식별자가 들어 있다 - Windows는 HFONT이고, GTK+는 PangoFontDescription*이다. 식별자를 소유하지 않기 때문에, 플랫폼 폰트 객체는 자신의 소멸자에서 제거되지 않는다. 클라이언트 코드는 적절한 시간에 Destroy를 호출해야 한다.
Surface는 각 플랫폼에서 그래픽 그리기 연산이 수행되는 곳이라는 개념 위에 세운 추상 레이어이다. 창과 같이 이미 생성된 그리기 장소를 래핑할 수도 있으며 또는 그곳에 그려 넣을 비트맵을 만드는데 사용할 수도 있다. 비트맵은 나중에 또다른 표면 위에 복사할 수도 있다. 윈도우즈에서는 HDC를 래핑하며 HBITMAP을 래핑할 수도 있다. GTK+에서는 cairo_surface_t*를 래핑한다. 다른 플랫폼 종속적인 객체들은 그리기 조치를 수행할 필요가 있을 때마다 만들어진다 (그리고 올바르게 제거된다).
그리기 연산은 다각형, 라인, 사각형, 타원과 텍스트가 제공된다. 다른 세부정보와 더불어 텍스트의 높이와 너비를 측정할 수 있다. 연산은 사각형으로 자를 수 있다. 대부분의 호출은 상태정보가 없으며 모든 매개변수는 호출마다 전달된다. 이에 대한 예외는 라인 그리기로서 MoveTo를 호출한 다음 LineTo를 호출하여 수행된다.
Window는 플랫폼 창에 대하여 프록시로 행위한다. 창을 보여주며 옮기고 그리고 다시 그리며 없애는 일을 수행한다. 플랫폼 종속적인 창 식별자가 들어있다 - Windows는 HWND이고, GTK+는 GtkWidget*이다.
ListBox는 Window의 하위클래스이고 플랫폼 listbox에 대한 프록시로 행위한다. 아이템을 선택하고 열람하고 추가하는 것과 같은 메쏘드를 추가한다.
메뉴는 작은 도움자 클래스로서 팝업 메뉴를 구성한다. 안에 플랫폼 종속적인 메뉴 식별자가 포함되어 있다 - 윈도우즈는 HMENU이고, GTK+는 GtkMenu*이다. 메뉴를 구성하는데 있어서 대부분의 작업은 플랫폼 이벤트에 접근하는 일이며 그래서 플랫폼 이벤트와 API 레이어에서 이루어진다.
플랫폼 클래스는 플랫폼의 편의기능에 접근하는데 사용된다. 더블 클릭 속도나 크롬 컬러 같은 시스템 수준의 매개변수들은 Platform에서 사용할 수 있다. DebugPrintf같은 유틸리티 함수도 Platform에서 사용할 수 있다.
Scintilla 코드는 대부분 플랫폼에 독립적이다. 기본 클래스는 CellBuffer, ContractionState, Document, Editor, Indicator, LineMarker, Style, ViewStyle, KeyMap, ScintillaBase, CallTip, 그리고 AutoComplete로 이루어진다.
CellBuffer에는 텍스트와 스타일 정보, 언두 스택과 줄표식 할당 그리고 폴딩 구조가 들어 있다.
셀 안에는 문자 바이트와 그와 연관된 스타일 바이트가 들어 있다. 셀 버퍼의 현재 상태는 그 안에 텍스트와 일련의 줄 정보로 구성된 일련의 셀이다. 줄 정보에는 각 줄의 시작 위치와 각 줄에 할당된 표식들이 들어 있다.
언두스택에는 셀 버퍼에 대한 일련의 조치가 담겨 있다. 각 조치는 텍스트 삽입이나 삭제 또는 언두 시작 조치중 하나이다. 시작 조치는 일련의 텍스트 삽입과 삭제를 함께 묶는데 사용된다. 그래서 한꺼번에 환원할 수 있다. 언두 연산을 수행하면, 각 삽입이나 삭제가 역순으로 환원된다. 비슷하게, 리두는 각 조치를 버퍼에 순서대로 재적용한다. InsertString 같은 호출을 통하여 직접적으로 또는 언두나 리두를 통하여 문자가 버퍼에 삽입될 때마다, 그의 스타일 바이트는 처음에 0으로 설정된다. 클라이언트 코드는 각 문자를 필요에 맞게 스타일처리할 책임을 진다. 스타일 정보는 언두 조치에 저장되지 않는다.
문서는 CellBuffer가 포함되어 있으며 단어와 DBCS 문자 연속열 그리고 줄 끝 문자들과 같은 좀 높은 수준의 추상을 다룬다. 스타일 처리와 문서에 변화가 있으면 다른 객체들에게 고지하는 책임을 진다.
Editor 객체는 Scintilla의 중심이다. 문서를 보여주고 사용자 조치와 컨테이너로부터의 요구에 응답하는 책임을 진다. ContractionState, Indicator, LineMarker, Style, 그리고 ViewStyle 객체를 사용하여 문서를 보여주고 KeyMap 클래스를 사용하여 키 눌림을 함수에 짝지어 준다. 각 줄의 가시성은 ContractionState에 보관되며 화면 줄과 문서 줄 사이를 서로 짝지어 주는 책임을 진다.
여러 Editor 객체가 한 Document 객체에 부착될 수 있다. 문서를 변경하면 DocWatcher 메커니즘을 통하여 편집기들에게 방송된다.
ScintillaBase는 Editor의 하위클래스이고 창 특징들이 추가된다. 여기에는 콜팁 보여주기, 자동 완성 리스트 그리고 문맥 메뉴가 포함된다. 이 특징들은 CallTip과 AutoComplete 객체를 사용한다. 이 클래스는 선택적이다. 그래서 가볍게 Scintilla를 구현하면 무시해도 된다. 추가 기능이 꼭 필요하지 않다면 말이다.
플랫폼마다 다른 메커니즘을 사용하여 이벤트를 받는다. 윈도우즈 이벤트는 메시지와 COM을 통하여 수신한다. GTK+에서는 역호출 함수가 사용된다.
각 플랫폼에 대하여, 클래스는 ScintillaBase로부터 파생된다 (이는 또 Editor에서 파생됨). 윈도우즈에서는 ScintillaWin이고 GTK+에서는 ScintillaGTK이다. 이 클래스들은 플랫폼 이벤트 메커니즘에 접속하고 또 Editor와 ScintillaBase에 플랫폼마다 다른 가상 메쏘드를 구현하는 책임을 진다. 예를 들어, 이 레이어는 동기적인 윈도우즈 클립보드와 비동기적인 GTK+ 클립보드 사이의 차이점을 지원해야 한다.
외부 API는 이 레이어에 정의된다. 플랫폼마다 선호하는 API 스타일이 다르기 때문이다 - 윈도우즈에서는 메시지를 GTK+에서는 함수 호출을 선호한다. 이 또한 다중 API를 플랫폼에 정의할 수 있도록 해 주어야한다. 현재 GTK+에서 사용가능한 API는 Windows API와 비슷하며 플랫폼 관례도 따르지 않는다. 플랫폼 관례를 따르는 보조 API는 여기에서 구현할 수 있다.